C 仅对任意文件使用预处理器?

C 仅对任意文件使用预处理器?,c,gcc,clang,c-preprocessor,C,Gcc,Clang,C Preprocessor,我想证明预处理器完全独立于构建过程。与C语言相比,它是另一种语法和词法。事实上,我想说明预处理器可以应用于任何类型的文件 所以我有一个任意文件: #define FOO #ifdef FOO I am foo #endif # # # Something #pragma Hello World 我想这会管用的: $ gcc -E test.txt -o- gcc: warning: test.txt: linker input file unus

我想证明预处理器完全独立于构建过程。与C语言相比,它是另一种语法和词法。事实上,我想说明预处理器可以应用于任何类型的文件

所以我有一个任意文件:

#define FOO    
#ifdef FOO    
I am foo    
#endif    
#
#
#    
Something    
#pragma Hello World
我想这会管用的:

$ gcc -E test.txt -o-
gcc: warning: test.txt: linker input file unused because linking not done
不幸的是,它只适用于以下情况:

$ cat test.txt | gcc -E -

GCC为什么会出现此错误?

您需要告诉
GCC
它是一个C文件

gcc -xc -E test.txt

您可以使用C预处理器,
cpp
(或者更传统的形式,
/lib/cpp
):


C编译器使用文件名后缀作为必须编译的文件(以
.C
结尾)的指示符,对于以
.s
结尾的文件,它将汇编程序
称为(1)和在 F./Cort>中的文件称为FORTRAN编译器,对于cc.<代码>转换为C++编译。
实际上,通常情况下,C编译器会将所有不匹配的内容都作为链接器文件,因此,一旦您将链接器文件传递给它,它就会尝试链接它,并调用链接器
ld(1)
。这就是您的
.txt
文件所发生的情况。链接器有一些类似的方法来根据对象或共享对象文件识别
ld(1)
脚本

顺便说一句,CPP语言确实是一种宏语言,但与C语言有一些无法避免的相似之处。它至少要识别C标识符,因为宏名称与C标识符具有相同的语法,并且必须检查标识符是否与宏名称匹配。在另一边。。。它必须识别C注释和C字符串(它确实消除了编译器的注释),因为宏扩展不会进入它们内部进行扩展,它还必须识别括号(它们用于宏参数检测和用于分隔参数的
符号)。它还可以识别(在宏字符串中)标记
(将参数字符串化)和
#
(将两个符号连接并合并为一个)(最后一个运算符必须强制cpp识别几乎所有的C标记,因为如果您试图将类似
+#+
的内容合并到
+
中,它必须检查错误,这是一个错误)

因此,结论是:cpp不必将整个C语法作为一种语言来实现,但C语言的标记必须被几乎完全识别。C语言的标准迫使C预处理器对输入进行标记化,因此可以使用
操作符来合并标记(并检查有效性)这意味着,如果定义宏,如:

#define M(p) +p
然后你把它叫做:

a = +M(-c);
您将得到一个类似以下内容的字符串:

a = + +-c;
在输出中(它将在两个
+
符号之间插入一个空格,这样它们就不会合并到
+
运算符中。符号
+
-
在一起,因为它们永远不会作为一个标记进行扫描)请参见下一个示例(输入前面有
符号)

正如您在本例中所看到的,合并
a
300
很好,因为一个令牌生成一个标识符,该标识符是有效的,
cpp(1)
不会抱怨,但是当合并
a
300.2
时,生成的令牌
a300.2
在C中不是有效的令牌,因此被拒绝(它也没有连接,并且工具插入了一个空格,以使编译器将这两个标记视为单独的——如果它将这两个标记连接在一起,它们将被扫描为标记
a300
.2


如果您想使用与语言无关的宏预处理程序,请考虑使用<代码> M4(1)

作为一种宏语言。它在许多方面都比
cpp
强大得多。但是要注意,由于它允许宏扩展的复杂性,它很难学习。

直接使用
cpp
对您来说重要吗?或者这对您的演示没有意义吗?
a = +M(-c);
a = + +-c;
$ cpp - <<EOF
> #define M(p) +p
> a = +M(p);
> b = -M(p);
> p = +M(+p);
> p = +M(-p);
> EOF
# 1 "<stdin>"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 346 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "<stdin>" 2

a = + +p;
b = -+p;
p = + + +p;
p = + +-p;
$ cpp - <<EOF
#define M(a,b) a##b
> a = M(a+,+b)
> a = M(a+,-b)
> a = M(a,+b)
> a = M(a,b)
> a = M(a,300)
> a = M(a,300.2)
> EOF
>> <stdin>:3:5: error: pasting formed '+-', an invalid preprocessing token
>> a = M(a+,-b)
>>     ^
>> <stdin>:1:17: note: expanded from macro 'M'
>> #define M(a,b) a##b
>>                 ^
>> <stdin>:4:5: error: pasting formed 'a+', an invalid preprocessing token
>> a = M(a,+b)
>>     ^
>> <stdin>:1:17: note: expanded from macro 'M'
>> #define M(a,b) a##b
>>                 ^
>> <stdin>:7:5: error: pasting formed 'a300.2', an invalid preprocessing token
>> a = M(a,300.2)
>>     ^
>> <stdin>:1:17: note: expanded from macro 'M'
>> #define M(a,b) a##b
>>                 ^
>> 3 errors generated.
# 1 "<stdin>"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 346 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "<stdin>" 2

a = a++b
a = a+-b
a = a+b
a = ab
a = a300
a = a 300.2