在连接带符号数字的令牌时,预处理器似乎增加了一个空格。 我尝试过:
#define DECL_FL(IE) 1e##IE##f
float val[] =
{
DECL_FL(12),
DECL_FL(-12),
DECL_FL(+12),
};
我运行预处理器:
$ gcc test.c -E
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "test.c"
float val[] =
{
1e12f,
1e- 12f,
1e+ 12f,
};
数组中的第一个元素正确。对于其他两个元素,在数字和符号之间添加一个空格。
为什么预处理器要添加空间?我该如何避免呢?
答案 0 :(得分:2)
简短的版本是+12
不是预处理器令牌,-12
也不是;而是每个都是两个预处理器令牌(即+
和-
是标点符号; 12
分别是pp数)。
我们实际上是在处理pp-number,因此这是pp-number的语法规则:
pp-number:
digit
. digit
pp-number digit
pp-number identifier-nondigit
pp-number e sign
pp-number E sign
pp-number p sign
pp-number P sign
pp-number .
请注意,1
,1e+
,1e+12
和1e+12f
都是pp编号,而+12
和-12
不是pp编号。这是在咬你。
根据预处理程序规则,替换列表中的参数由参数令牌序列替换;然后,将应用每个##
。该应用程序删除##
并将前面的令牌连接到后面的令牌。如果该组合不是有效的预处理器令牌,则结果不确定。 (作为参考,预处理器令牌可以是标头名称,标识符,pp-number,字符常量,字符串文字,标点符号或不属于这些字符的非空白字符;仅此而已。)
在IE为+12的情况下应用1e ## IE ## f时,实际上是在做<1e
> ## <{+
> <12
> ## <{ {1}}>,使用尖括号表示各个标记。两种粘贴方式,无论顺序如何(这都很好,因为未指定##顺序),都将生成有效的pp号<f
>和<1e+
>。但是结果使您只能使用<12f
> <1e+
>而不是所需的<12f
>。
如何避免呢?
不幸的是,您必须放弃传递1e+12f
和+12
令牌序列作为参数。您可以接受-12
作为两个参数,但是在逐步组合它们时要小心,因为+, 12
运算符的顺序未指定,并且##
不是有效的预处理器令牌(否则它可能有效,但不允许...并且 情况可能是噩梦般的定时炸弹):
+12
...或者您可以简单地使用符号专用宏;严格来说,由于#define PASTE(A,B) A##B
#define DECL_FL(IE) 1e##IE##f
#define DECL_FL_SGN(S,IE) PASTE(1e##S,IE##f)
float val[] =
{
DECL_FL(12),
DECL_FL_SGN(+,12),
DECL_FL_SGN(-,12),
};
和1e12f
是相同的值(除非他们只运行预处理程序,否则任何人都不会看到它),您只能使用两个宏:
1e+12f
答案 1 :(得分:-1)
##
是令牌粘贴运算符,如果使用后未形成有效令牌,则此方法将无效,因为C 1e+12f
不是有效的预处理令牌,因此它正在尝试插入空间或可能导致意外的行为,您可以在以下文档中找到它。
http://gcc.gnu.org/onlinedocs/cpp/Concatenation.html