C 编译器使用文件名后缀作为必须编译的文件的指示符(以.c 结尾)只需要链接的文件(以.o 或.so 结尾)以.s 结尾的它调用汇编器as(1),对于以.f 结尾的文件,它调用fortran 编译器,对于.cc,它切换到C++ 编译。
确实,通常,C 编译器会将它们不匹配的所有内容都作为链接器文件,因此一旦您将链接器文件传递给它,它就会尝试链接它,并调用链接器ld(1)。这就是您的.txt 文件所发生的情况。链接器有一些类似的方法来识别 ld(1) 脚本对对象或共享对象文件。
顺便说一句,CPP 语言确实是一种宏语言,但与 C 有一些无法避免的相似之处。它至少可以识别 C 标识符,因为宏名称与 C 标识符具有相同的语法,并且它必须检查标识符是否与宏名称匹配。另一方面......它必须识别 C cmets 和 C 字符串(它确实消除了编译器的 cmets),因为宏扩展不会在它们内部展开,并且它还必须识别括号(它们被认为是宏参数检测和,符号,用于分隔参数)。它还识别(在宏字符串内)标记 #(将参数字符串化)和 ##(将两个符号连接并合并为一个)(最后一个运算符必须强制 cpp 识别几乎任何 C 标记,因为它如果您尝试将+##+ 之类的内容合并到++ 中,则必须检查错误,这是一个错误)
因此,结论是: cpp 不必将整个 C 语法实现为一种语言,但 C 语言的标记必须被识别几乎完全。 C 语言的标准强制 c 预处理器对输入进行标记,因此## 运算符可用于合并标记(并检查有效性)这意味着,如果您定义如下宏:
#define M(p) +p
然后你这样称呼它:
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;
另一个示例将显示解析标记的更多困难(输入用> 分隔,stderr 用>> 分隔,stdout 不加引号):
$ 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
正如您在此示例中所见,合并 a 和 300 很好,因为一个令牌生成一个标识符,这是有效的,cpp(1) 不会抱怨,但是当合并 a 和 @987654353 @ 生成的标记 a300.2 不是 C 中的有效标记,因此它被拒绝(它也没有连接,并且工具插入了一个空格,以使编译器将两个标记视为单独的 --- 是否应该将两者连接在一起,它们会被扫描为令牌a300 和.2)。
如果您想使用独立于语言的宏预处理器,请考虑使用m4(1) 作为宏语言。它在很多方面都比cpp 强大得多。但请注意,由于它允许的宏扩展的复杂性,它很难学习。