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>
这里注意1
、1e+
、1e+12
、1e+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),
};
...或者您可以简单地使用符号特定的宏;并且严格来说,因为 1e12f
和 1e+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),
};
似乎预处理器在连接有符号数字的标记时添加了 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>
这里注意1
、1e+
、1e+12
、1e+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),
};
...或者您可以简单地使用符号特定的宏;并且严格来说,因为 1e12f
和 1e+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),
};