我试图同时理解三字母和有向字母,而不是使用它们。
我读过那篇文章,我明白:
- 将三元组转换为相应的字符应始终由预处理器在实际编译开始之前完成。
- 将有向图转换为相应的字符应由编译器执行。
这是真的?
在编译过程的第一阶段,在预处理器词法分析器分析字符流以生成预处理器标记之前,三字母序列确实被替换为相应的字符。
下一个阶段处理转义的换行符,即:\
紧跟换行符的实例,从字符流中删除。请注意,\
可以由第一阶段生成作为??/
trigraph的替代品。
然后,词法分析器分析字符流以生成预处理标记,例如[
和 ,<:
它们是相同标记的替代拼写,就像1e1
and一样1E1
,因此<:
不会被替换,[
它是产生相同标记的不同字符序列。
三元图不能通过在宏扩展中使用预处理器操作符进行标记粘贴来生成##
,但有向图可以。
这是一个小示例程序来说明此过程,包括??/
扩展为 的三元组的特殊处理\
,因此可用于两行拆分的二元组中间:
#include <stdio.h>
#define STR(x) #x
#define xSTR(x) STR(x)
#define glue(a,b) a##b
int main() {
puts(STR(??!));
puts(STR('??!'));
puts(STR("??!"));
puts(STR(<:));
puts(STR('<:'));
puts(STR("<:"));
puts(STR(<\
:));
puts(STR(<??/
:));
puts(STR('<\
:'));
puts(STR("<\
:"));
puts(STR(glue(<,:)));
puts(xSTR(glue(<,:)));
return 0;
}
输出:
chqrlie $ make lexing && ./lexing
clang -O3 -funsigned-char -std=c11 -Weverything -Wwrite-strings -lm -o lexing lexing.c
lexing.c:8:14: warning: trigraph converted to '|' character [-Wtrigraphs]
puts(STR(??!));
^
lexing.c:9:15: warning: trigraph converted to '|' character [-Wtrigraphs]
puts(STR('??!'));
^
lexing.c:10:15: warning: trigraph converted to '|' character [-Wtrigraphs]
puts(STR("??!"));
^
lexing.c:18:15: warning: trigraph converted to '\' character [-Wtrigraphs]
puts(STR(<??/
^
4 warnings generated.
|
'|'
"|"
<:
'<:'
"<:"
<:
<:
'<:'
"<:"
glue(<,:)
<:
二合字母不会“转换为相应的字符”。字符串文字"<:"
包含两个字符<
和:
(加上一个空终止符)。"??("
如果您有一个支持三元组的编译器,请将其与字符串进行对比。
<:
只是一个与 . 具有完全相同的句法意义的标记[
。但它永远不会转换为[
. 如果将它传递给 stringify 运算符#
,您将获得字符串"<:"
。