有向字母和三字母不能一起工作?
Digraph and trigraph can't work together?
我正在学习二字母和三字母,这是我看不懂的代码。 (是的,我承认非常丑。)
这段代码可以编译:
#define _(s) s%:%:s
main(_(_))
<%
__;
%>t
这段代码也可以编译:
#define _(s) s??=??=s
main(_(_))
<%
__;
%>
但是下面两段代码都无法通过:
#define _(s) s%:??=s
main(_(_))
<%
__;
%>
和
#define _(s) s??=%:s
main(_(_))
<%
__;
%>
这确实让我感到困惑:由于前两段代码可以编译,我想二字母和三字母的展开都发生在宏展开之前。那么为什么二字母三字母一起使用会编译不通过呢?
二字母和三字母完全不同。三字母在翻译的第 1 阶段被替换,[见注释 1] 在源代码被分离成标记之前。 Digraphs 是标记,它是其他标记的替代拼写,因此在源被分离成标记之前它们没有意义。 (单词 "digraph" 不是很准确;使用它是因为它类似于 "trigraph",但二合字母集包括由四个字符组成的 %:%:
。)
因此在完成任何标记分析之前,??=
被替换为 #
。但是%:
只是一个token,和#
.
的意思是一样的
此外,%:%:
是一个与##
同义的记号。但是 %:#
是两个标记(%:
和 #
),这是不合法的,因为 stringify 运算符(无论拼写为 %:
还是 #
)只能跟在后面通过宏参数。 [见注释 2] 如果 #
是三字母替换的结果,它也不会变得不合法。
如 所示,二字母和三字母之间的一个重要区别是三字母也适用于字符串。即使您的键盘缺少方括号和八字形,二合字母仍可让您编写 C 代码,但它们无法帮助您打印出这些字符。
注释(标准引用):
§5.1.1.2,翻译阶段,第 1 段:
The precedence among the syntax rules of translation is specified by the following phases.
- Physical source file multibyte characters are mapped, in an implementation-defined manner, to the source character set (introducing new-line characters for end-of-line indicators) if necessary. Trigraph sequences are replaced by corresponding single-character internal representations.
§6.10.3.2,# 运算符,第 1 段:
Each # preprocessing token in the replacement list for a function-like macro shall be
followed by a parameter as the next preprocessing token in the replacement list.
对于学术方面,请查看 rici 的有据可查的答案。
对于常识而言,除非你已经非常精通C,否则二字母和三字母是完全没有用的,你甚至不应该在这个问题上浪费任何时间。它们的发明是为了支持 non-US 7 位字符集,这些字符集在 1980 年代仍在大型机和一些小型计算机上使用。这些字符集缺少 C 语言所需的一些标点符号,例如 #
、{
、}
等,以便为 space 等区域设置特定字符制作 space 14=]、é
、è
...(请原谅我的法语)。
即使在我使用了很长时间的这些系统上,也从未使用过三字母,因为存在丑陋的实用替代品:在法语系统上,输入了重音字母,例如 é
和 è
但会被 C 编译器解释为 {
和 }
。它使 C 编程变得晦涩难懂,并促使许多程序员改用美式 QWERTY 键盘和语言环境(或等效语言)。
这已经成为过去,只有历史意义,除了拼写错误、混淆和令人讨厌的面试问题外,你永远不会看到这些东西在起作用。
关于后者,我忍不住发了这个:
I cannot get fnmatch
to validate my date template even if I force a valid date, what is wrong with this code:
#include <stdio.h>
#include <fnmatch.h>
int main() {
char date[] = "01/01/1988";
if (fnmatch("??/??/????", date, 0))
printf("invalid date format\n");
return 0;
}
我正在学习二字母和三字母,这是我看不懂的代码。 (是的,我承认非常丑。)
这段代码可以编译:
#define _(s) s%:%:s
main(_(_))
<%
__;
%>t
这段代码也可以编译:
#define _(s) s??=??=s
main(_(_))
<%
__;
%>
但是下面两段代码都无法通过:
#define _(s) s%:??=s
main(_(_))
<%
__;
%>
和
#define _(s) s??=%:s
main(_(_))
<%
__;
%>
这确实让我感到困惑:由于前两段代码可以编译,我想二字母和三字母的展开都发生在宏展开之前。那么为什么二字母三字母一起使用会编译不通过呢?
二字母和三字母完全不同。三字母在翻译的第 1 阶段被替换,[见注释 1] 在源代码被分离成标记之前。 Digraphs 是标记,它是其他标记的替代拼写,因此在源被分离成标记之前它们没有意义。 (单词 "digraph" 不是很准确;使用它是因为它类似于 "trigraph",但二合字母集包括由四个字符组成的 %:%:
。)
因此在完成任何标记分析之前,??=
被替换为 #
。但是%:
只是一个token,和#
.
此外,%:%:
是一个与##
同义的记号。但是 %:#
是两个标记(%:
和 #
),这是不合法的,因为 stringify 运算符(无论拼写为 %:
还是 #
)只能跟在后面通过宏参数。 [见注释 2] 如果 #
是三字母替换的结果,它也不会变得不合法。
如
注释(标准引用):
§5.1.1.2,翻译阶段,第 1 段:
The precedence among the syntax rules of translation is specified by the following phases.
- Physical source file multibyte characters are mapped, in an implementation-defined manner, to the source character set (introducing new-line characters for end-of-line indicators) if necessary. Trigraph sequences are replaced by corresponding single-character internal representations.
§6.10.3.2,# 运算符,第 1 段:
Each # preprocessing token in the replacement list for a function-like macro shall be followed by a parameter as the next preprocessing token in the replacement list.
对于学术方面,请查看 rici 的有据可查的答案。
对于常识而言,除非你已经非常精通C,否则二字母和三字母是完全没有用的,你甚至不应该在这个问题上浪费任何时间。它们的发明是为了支持 non-US 7 位字符集,这些字符集在 1980 年代仍在大型机和一些小型计算机上使用。这些字符集缺少 C 语言所需的一些标点符号,例如 #
、{
、}
等,以便为 space 等区域设置特定字符制作 space 14=]、é
、è
...(请原谅我的法语)。
即使在我使用了很长时间的这些系统上,也从未使用过三字母,因为存在丑陋的实用替代品:在法语系统上,输入了重音字母,例如 é
和 è
但会被 C 编译器解释为 {
和 }
。它使 C 编程变得晦涩难懂,并促使许多程序员改用美式 QWERTY 键盘和语言环境(或等效语言)。
这已经成为过去,只有历史意义,除了拼写错误、混淆和令人讨厌的面试问题外,你永远不会看到这些东西在起作用。
关于后者,我忍不住发了这个:
I cannot get
fnmatch
to validate my date template even if I force a valid date, what is wrong with this code:
#include <stdio.h>
#include <fnmatch.h>
int main() {
char date[] = "01/01/1988";
if (fnmatch("??/??/????", date, 0))
printf("invalid date format\n");
return 0;
}