有向图是由编译器转换的,而三字母由预处理器转换的吗?
Are digraphs transformed by a compiler and trigraphs transformed by a preprocessor?
我试图同时理解三字母和二字母而不是使用它们。
我已阅读 并了解到:
- 将三字母转换为相应的字符应始终由预处理器在实际编译开始之前完成。
- 将二合字母转换为相应的字符应由编译器执行。
这是真的吗?
二合字母没有“转换为相应的字符”。字符串文字 "<:"
包含两个字符 <
和 :
(加上空终止符)。如果你有一个支持三字母的编译器,将它与字符串 "??("
进行对比。
<:
只是一个标记,与 [
具有完全相同的句法意义。但它永远不会转换为 [
。如果将它传递给 stringify 运算符 #
,您将得到字符串 "<:"
.
在编译过程的第一阶段,在预处理器词法分析器分析字符流以生成预处理器标记之前,三字母序列确实被替换为相应的字符。
紧接着的下一个阶段处理转义的换行符,即:\
的实例紧跟一个换行符,它们从字符流中删除。 请注意,\
可以由第一阶段生成,以替代 ??/
三字母 。
词法分析器然后分析字符流以生成预处理标记,例如 [
和 <:
,它们是同一标记的替代拼写,就像 1e1
和 1E1
,因此 <:
不是 替换 为 [
,它是产生相同标记的不同字符序列。
三字母不能通过在宏扩展中使用 ##
预处理器运算符粘贴标记来生成,但二字母可以。
这里有一个小示例程序来说明这个过程,包括扩展到 \
的 ??/
三字母的特殊处理,因此可以在 2 上的二字母拆分中间使用行:
#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 运算符 #
,您将得到字符串 "<:"
.
在编译过程的第一阶段,在预处理器词法分析器分析字符流以生成预处理器标记之前,三字母序列确实被替换为相应的字符。
紧接着的下一个阶段处理转义的换行符,即:\
的实例紧跟一个换行符,它们从字符流中删除。 请注意,\
可以由第一阶段生成,以替代 ??/
三字母 。
词法分析器然后分析字符流以生成预处理标记,例如 [
和 <:
,它们是同一标记的替代拼写,就像 1e1
和 1E1
,因此 <:
不是 替换 为 [
,它是产生相同标记的不同字符序列。
三字母不能通过在宏扩展中使用 ##
预处理器运算符粘贴标记来生成,但二字母可以。
这里有一个小示例程序来说明这个过程,包括扩展到 \
的 ??/
三字母的特殊处理,因此可以在 2 上的二字母拆分中间使用行:
#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(<,:)
<: