我已经轻而易举地减少了我的问题:
#define STR_BEG "
#define STR_END "
int main()
{
char * s = STR_BEG abc STR_END;
printf("%s\n", s);
}
编译时,我收到以下错误:
static2.c:12:16: error: expected expression
char * s = STR_BEG abc STR_END;
^
static2.c:7:17: note: expanded from macro 'STR_BEG'
#define STR_BEG "
现在,如果我只是运行预处理器gcc -E myfile.c
,我得到:
int main()
{
char * s = " abc ";
printf("%s\n", s);
}
这正是我想要的,以及完全合法的结果代码。那么这笔交易是什么?
答案 0 :(得分:10)
宏并没有真正扩展"正确",因为这不是一个有效的C预处理器程序。正如Kerrek所说,预处理器并不完全在任意字符序列上工作 - 它适用于整个令牌。标记是与形成有效C代码的标记相同形式(或多或少)的标点符号,标识符,数字,字符串等。这些定义不描述有效的字符串 - 它们打开它们,并且在行结束之前无法关闭它们。因此,无效的令牌序列正被传递给预处理器。它设法从无效程序产生输出的事实可以说是方便的,但它并没有使它正确,它几乎肯定保证了预处理器的垃圾输出最多。您需要为它们终止字符串以形成整个令牌 - 现在它们形成垃圾输入。
要将标记或标记序列实际包装在引号中,请使用字符串化运算符#
:
#define STRFY(A) #A
STRFY(abc) // -> "abc"
如果你在启用-Wall
标志的情况下编译或预处理,那么GCC和类似的编译器会警告你这样的错误。
(我假设你只是在尝试编译为C时才会出错,但是当你在两次传递中执行时却没有,因为在编译器内部,它会保留这些信息,这些信息是"破坏"令牌如果你写出一个中间文件,然后在第二次传递中编译预处理的源代码就会丢失...如果是这样,这是一个实现细节,不要依赖它。)
实际问题的一种可能解决方案可能如下所示:
#define LPR (
#define start STRFY LPR
#define end )
#define STRFY(A) #A
#define ID(...) __VA_ARGS__
ID(
char * s = start()()()end; // -> char * s = "()()()";
)
但ID
包装是必要的。没有它,没有办法做到这一点(它可以绕过任意数量的行,甚至是你的整个程序,但它必须存在的原因在其他问题中得到很好的解释)。