有向图和三字图不能一起工作吗?

时间:2016-01-04 00:41:16

标签: c macros c-preprocessor digraphs trigraphs

我正在学习有向图和三字母,这是我无法理解的代码。 (是的,我承认它非常难看。)

此代码可以编译:

#define _(s) s%:%:s

main(_(_))
<%
    __;
%>t

这段代码也可以编译:

#define _(s) s??=??=s

main(_(_))
<%
    __;
%>

但是,以下两段代码都不能编译:

#define _(s) s%:??=s

main(_(_))
<%
    __;
%>

#define _(s) s??=%:s

main(_(_))
<%
    __;
%>

这确实让我感到困惑:由于前两段代码可以编译,我想digraph和trigraph的扩展都发生在宏扩展之前。那么为什么在将digraph和trigraph一起使用时它们能够编译呢?

2 个答案:

答案 0 :(得分:2)

有向图和三角形是完全不同的。在翻译的第1阶段,[参见注释1],在源代码被分成标记之前,Trigraph被替换。 Digraph是令牌,它们是其他令牌的替代拼写,所以直到源被分成令牌之后它们才有意义。 (“有向图”这个词不是很准确;因为它类似于“三字母”而使用它,但是有向图集包括%:%:,它由四个字符组成。)

在完成任何令牌分析之前,??=将替换为#。但%:只是一个标记,其含义与#相同。

此外,%:%:是与##具有相同含义的标记。但是%:#是两个令牌(%:#),这是不合法的,因为stringify运算符(拼写为%:#)只能被跟踪通过宏参数。 [见注2]如果#是三角形替换的结果,它就不会变得非法。

the hilarious snippet in chqrlie's answer所示,有向图和三字符之间的一个重要区别是三字符也可用于字符串。 Digraphs允许你编写C代码,即使你的键盘没有括号和octothorpi,但它们无法帮助你打印出这些字符。

注释(标准报价):

  1. §5.1.1.2,翻译阶段,第1段:

      

    翻译语法规则的优先级由以下阶段指定。

         
        
    1. 物理源文件多字节字符以实​​现定义的方式映射到源字符集(如果需要,引入行尾指示符的换行符)。 Trigraph序列由相应的单字符内部表示替换。
    2.   
  2. §6.10.3.2, #erler ,第1段:

      

    类似函数宏的替换列表中的每个#preprocessing token都应该是   后跟一个参数作为替换列表中的下一个预处理标记。

答案 1 :(得分:2)

对于学术方面,请看看rici记录良好的答案。

对于常识方面,除非你已经非常精通C,否则有向图和三字母完全没用,你甚至不应该浪费任何时间来讨论这个问题。它们被发明为一种支持非美国7位字符集的方法,这些字符集在20世纪80年代仍在大型机和一些小型计算机上使用。这些字符集缺少C语言所需的一些标点符号,例如#{}等。

即使在我使用过一段时间的这些系统上,也从未使用过三角形,因为存在丑陋的实用替代方案:在法语系统上,输入了éè等重音字母但是由C编译器解释为{}。它使C编程模糊不清,并促使许多程序员切换到美国QWERTY键盘和Locale(或等效的)。

这是过去的事情,只有历史感兴趣,除了错别字,混淆和令人讨厌的面试问题,你永远不会看到这些在行动中。

关于后者,我无法抗拒发布这个:

  

即使我强制使用有效日期,我也无法让fnmatch验证我的日期模板,这段代码有什么问题:

#include <stdio.h>
#include <fnmatch.h>
int main() {
    char date[16] = "01/01/1988";
    if (fnmatch("??/??/????", datebuf, 0))
        printf("invalid date format\n");
    return 0;
}