c预处理器在将数字与符号连接时添加space

c preprocessor add a space when concatenate numbers with sign

似乎预处理器在连接有符号数字的标记时添加了 space。 我试过这个:

#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,
};

数组中的第一个元素是正确的。对于其他两个元素,在数字和符号之间添加一个space。
为什么预处理器添加一个space?我怎样才能避免它?

## 是令牌粘贴运算符,如果在使用后未形成有效令牌,这将不起作用,因为根据 C 1e+12f 不是有效的预处理器令牌,因此它正在尝试插入 space 否则可能会导致意外行为,您可以在以下文档中找到它。

http://gcc.gnu.org/onlinedocs/cpp/Concatenation.html

简而言之,+12 不是预处理器标记,-12 也不是;相反,它们中的每一个都是两个预处理器标记(即,+- 是标点符号;12 分别是 pp-number)。

我们实际上是在处理 pp-number,所以这里是 pp-number 的语法规则:

<em>pp-number</em>: <em>位数</em> <strong>.</strong> <em>位数</em> <em>pp-number</em> <em>位数</em> <em>pp-number</em> <em>identifier-nondigit</em> <em>pp-number</em> <strong>e</strong> <em>sign</em> <em>pp-number</em> <strong>E</strong> <em>sign</em> <em>pp-number</em> <strong>p</strong> <em>sign</em> <em>pp-number</em> <strong>P</strong> <em>sign</em> <em>pp-number</em> <strong>.</strong> 这里注意11e+1e+121e+12f都是pp-number,而+12-12不是.这就是困扰你的地方。

根据预处理器规则,替换列表中的参数被参数标记序列替换;然后,应用每个 ##。应用程序删除 ## 并将前面的标记连接到后面的标记。如果该组合不是有效的 preprocessor-token,则结果未定义。 (作为参考,preprocessor-token 可以是 header 名称、标识符、pp-number、character-constant、string-literal、标点符号或 non-whitespace 字符那不是其中之一;就是这样)。

在 IE 为 +12 的情况下应用 1e##IE##f 时,您实际上是在执行 <1e>##<+><12>## <f>,使用尖括号表示单个标记。无论顺序如何(这很好,因为 ## 顺序未指定),这两种粘贴都将生成有效的 pp-numbers <1e+> 和 <12f>。但结果是 <1e+><12f> 而不是所需的 <1e+12f>。

How can I avoid it?

不幸的是,您不得不放弃将 +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),
};

...或者您可以简单地使用符号特定的宏;并且严格来说,因为 1e12f1e+12f 是相同的值(而且没有人会看到它,除非他们只是 运行 预处理器),你可以只使用两个宏:

#define DECL_FL(IE) 1e##IE##f
#define DECL_FL_E_NEG(IE) 1e-##IE##f
float val[] = 
{
    DECL_FL(12),
    DECL_FL_E_NEG(12),
    DECL_FL(12),
};