- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试编写一个程序,其中一些函数的名称取决于某个宏变量的值,宏变量如下:
#define VARIABLE 3
#define NAME(fun) fun ## _ ## VARIABLE
int NAME(some_function)(int a);
不幸的是,宏 NAME()
把它变成了
int some_function_VARIABLE(int a);
而不是
int some_function_3(int a);
所以这显然是错误的做法。幸运的是,VARIABLE 的不同可能值的数量很少,所以我可以简单地执行 #if VARIABLE == n
并分别列出所有情况,但是有没有聪明的方法来做到这一点?
最佳答案
$ cat xx.c
#define VARIABLE 3
#define PASTER(x,y) x ## _ ## y
#define EVALUATOR(x,y) PASTER(x,y)
#define NAME(fun) EVALUATOR(fun, VARIABLE)
extern void NAME(mine)(char *x);
$ gcc -E xx.c
# 1 "xx.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "xx.c"
extern void mine_3(char *x);
$
在对另一个答案的评论中,Cade Roux asked为什么这需要两个级别的间接寻址。轻率的回答是因为这就是标准要求它工作的方式;您往往会发现您也需要字符串化运算符的等效技巧。
C99 标准的第 6.10.3 节介绍了“宏替换”,第 6.10.3.1 节介绍了“参数替换”。
After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list, unless preceded by a
#
or##
preprocessing token or followed by a##
preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.
在调用NAME(mine)
中,参数是'mine';它已完全扩展为“我的”;然后将其替换为替换字符串:
EVALUATOR(mine, VARIABLE)
现在发现了宏 EVALUATOR,参数被隔离为“mine”和“VARIABLE”;后者然后完全扩展为“3”,并代入替换字符串:
PASTER(mine, 3)
this 的操作包含在其他规则中(6.10.3.3 'The ## operator'):
If, in the replacement list of a function-like macro, a parameter is immediately preceded or followed by a
##
preprocessing token, the parameter is replaced by the corresponding argument’s preprocessing token sequence; [...]For both object-like and function-like macro invocations, before the replacement list is reexamined for more macro names to replace, each instance of a
##
preprocessing token in the replacement list (not from an argument) is deleted and the preceding preprocessing token is concatenated with the following preprocessing token.
因此,替换列表包含 x
后跟 ##
以及 ##
后跟 y
;所以我们有:
mine ## _ ## 3
并消除 ##
标记并连接两边的标记将“我的”与“_”和“3”组合起来产生:
mine_3
这是期望的结果。
如果我们查看原始问题,代码是(改编为使用“我的”而不是“some_function”):
#define VARIABLE 3
#define NAME(fun) fun ## _ ## VARIABLE
NAME(mine)
NAME 的参数显然是“我的”并且已完全展开。
遵循6.10.3.3的规则,我们发现:
mine ## _ ## VARIABLE
当 ##
运算符被消除时,映射到:
mine_VARIABLE
与问题中报告的完全一样。
Is there any way do to this with the traditional C preprocessor which does not have the token pasting operator
##
?
可能会,也可能不会——这取决于预处理器。标准预处理器的优点之一是它具有可靠工作的功能,而准标准预处理器有不同的实现。一个要求是当预处理器替换注释时,它不会像 ANSI 预处理器那样生成空格。 GCC (6.3.0) C 预处理器满足此要求; XCode 8.2.1 中的 Clang 预处理器没有。
当它工作时,它就完成了工作(x-paste.c
):
#define VARIABLE 3
#define PASTE2(x,y) x/**/y
#define EVALUATOR(x,y) PASTE2(PASTE2(x,_),y)
#define NAME(fun) EVALUATOR(fun,VARIABLE)
extern void NAME(mine)(char *x);
请注意 fun,
和 VARIABLE
之间没有空格 — 这很重要,因为如果存在,它会被复制到输出中,您最终会得到mine_ 3
作为名称,当然,这在语法上是无效的。 (现在,请问我可以把头发弄回来吗?)
使用 GCC 6.3.0(运行 cpp -traditional x-paste.c
),我得到:
# 1 "x-paste.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "x-paste.c"
extern void mine_3(char *x);
使用 XCode 8.2.1 的 Clang,我得到:
# 1 "x-paste.c"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 329 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "x-paste.c" 2
extern void mine _ 3(char *x);
那些空间破坏了一切。我注意到两个预处理器都是正确的;不同的准标准预处理器表现出这两种行为,这使得 token 粘贴在尝试移植代码时成为一个极其烦人且不可靠的过程。带有 ##
符号的标准从根本上简化了这一点。
可能还有其他方法可以做到这一点。但是,这不起作用:
#define VARIABLE 3
#define PASTER(x,y) x/**/_/**/y
#define EVALUATOR(x,y) PASTER(x,y)
#define NAME(fun) EVALUATOR(fun,VARIABLE)
extern void NAME(mine)(char *x);
GCC 生成:
# 1 "x-paste.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "x-paste.c"
extern void mine_VARIABLE(char *x);
接近,但没有骰子。当然,YMMV 取决于您使用的预标准预处理器。坦率地说,如果您遇到不合作的预处理器,安排使用标准 C 预处理器代替准标准预处理器(通常有一种适当配置编译器的方法)可能比花很多时间尝试找出完成这项工作的方法。
关于c - 我怎样才能与 C 预处理器连接两次并扩展一个宏,如 "arg ## _ ## MACRO"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1489932/
过去几天我一直试图解决这个问题,但我做不到。我正在尝试生成 _ _ _ 形式的随机数。 _ _ _ _ 小数点前 3 位,然后是 4 位小数。 非常感谢任何帮助。谢谢, 院长 最佳答案 您发布的代码有
我的方法有问题。我需要从主类调用的方法的输出打印我: 需要这个输出:_ _ _ _ _ 我知道我可以将 System 的静态方法放入循环中,但这不是我想要的解决方案。我需要它来打印主类中方法的输出。
我正在学习 Scala,有一个非常基本的问题。考虑以下两个使用占位符语法的表达式 - // Syntax A val fnA = (_: Int, _: Int) => _ / _ // Synta
我正在使用图书馆 URLEmbeddedView 它在其库中定义了以下代码: func addConstraints(with view: UIView, center: CGPoint, multi
我一直在许多受人尊敬的文档中看到这个相当令人尴尬的事情:_|_ 或 (_|_) 找不到它的定义(Google 不能很好地处理符号)。那到底是什么呢? 最佳答案 来自 here :- Bottom Th
,_,( ){ ,_,| ,_,&};,_, 不知道是什么意思... 看起来像一个 bash 命令,但它可能是 s bash shell 指令或其他东西如果有人可以帮助理解这一点,我们将不胜感激。当我
所以我正在尝试构建一个函数,它接受一个元组列表并找到具有最大第二个元素的元组。但是我遇到了模式匹配错误。 这是我的代码。 resultTuple :: [((Int,Int),Int)] ->
我在 try Flow 编辑器中重现了我的情况,可以访问 here . 以下是链接发生问题时的代码: /* @flow */ type PayloadType = 1 | 2 | 3; type Tr
我在plfa读到这样一段代码。 import Relation.Binary.PropositionalEquality as Eq open Eq using (_≡_; refl; cong; s
这个问题在这里已经有了答案: Swift 3.0: compiler error when calling global func min(T,T) in Array or Dictionary e
是否有理由使用一个而不是另一个?似乎 _.some 和 _.map 更易于使用或适用于更多情况(根据我非常有限的经验),但从阅读它来看,它们听起来好像应该做同样的事情。我敢肯定还有其他这样的例子,我很
在 Xcode 7 Beta 中开始使用 Swift 2 后,出现错误 cannot invoke。是什么导致了这个问题? 我试图通过以下两个问题找出我的问题,但我仍然收到错误:Question 1
所以我玩了一会儿,试图写一些关于存在和变化的东西,我遇到了这段有趣的代码。 final case class Box[+T](val value: T) { def >>=[U](f: T =>
Here is the screenshot for the error. 遵循本教程 https://developers.google.com/places/ios-api/start 在本教程中
我正在为许多标准的 Underscore.js 函数重写底层代码,以提高我的 JavaScript 技能,但我有点受困于 _.every/ _.全部。似乎在库本身中,_.every/_.all 函数仅
我在 shell 脚本中多次看到他们在 if 比较中使用 "_",如下所示: if [ "_$str" = "_" ]; then ....; fi 上面的代码通过比较 if [ "_$str"= "
我正在尝试快速过滤字典: var data: [String: String] = [:] data = data.filter { $0.1 == "Test" } 上面的过滤器代码在 Swift
我在 Entity Framework 核心映射方面遇到了问题。我收到此异常“不支持从‘付款’到‘购买。付款’的关系,因为拥有的实体类型‘购买’不能位于非所有权关系的主要方面。”在调试此功能的测试时。
我正在尝试模拟groovy.sql.Sql调用(查询,params [],闭包)类。 下面是我正在尝试在DatabaseService类文件中的方法。 public void getUsers(Lis
在阅读 dart 代码时,我经常看到一些仅使用下划线 _ 参数调用的函数。这让我困扰了一段时间,由于 flutter 改进了它的分析消息,我有了一些线索......但我觉得我并没有真正理解这个概念:-
我是一名优秀的程序员,十分优秀!