没想到吧,一行注释也能影响运行结果
也许你在某个段子里听说过,某行注释删掉后,程序竟然不能预期执行?真的会这样么?你还别不信。
见证“奇迹”
1//来源&#xff1a;公众号【编程珠玑】 2//作者&#xff1a;守望先生 3#include 4#include 5int main(void) 6{ 7 int a &#61; (int)sqrt(30); 8 //is sqrt(30) &#43; 1 > 5 ??/ 9 //故意让a&#43;&#43;&#xff0c;你别管为什么10 a&#43;&#43;;11 if(a > 5)12 printf("sqrt(30) &#43;1 > 5 ");13 else14 {15 printf("sqrt(30) &#43;1 <&#61; 5 ");16 }17 return 0;18}
编译运行&#xff1a;
1$ gcc -o main main.c -trigraphs2$ ./main3sqrt(30) &#43;1 > 5
作为受过九年义务教育的我们&#xff0c;一看就知道结果是对的&#xff0c;毕竟 5 * 5 <30 <6 * 6。
但是删掉第九行&#xff0c;再运行&#xff1a;
1$ ./main2sqrt(30) &#43;1 <&#61; 5
结果竟然变了&#xff01;&#xff01;
看到这里&#xff0c;细心的读者可能已经发现了其中的端倪&#xff0c;我也就不卖关子了。接下来就说说我们本次要提到的主角-三字符组(trigraph sequences)。
三字符组
我们都知道C语言里面有很多转义符号&#xff0c;例如&#xff1a;
1 换行符(LF)2 回车符(CR)3 水平制表符(HT)4b 退格符(BS)5’ 单引号6” 双引号7 反斜杠8......
当然还有很多&#xff0c;我就不一一列举了。这些符号在代码中都有特别的作用&#xff0c;或者无法直接输入&#xff0c;因此用转移符&#43;其他字符组合来代替。
同样的&#xff0c;早期的一些键盘可能没法输入一些特殊的符号&#xff0c;如&#xff1a;
1# $ &#64; [ ] ^ &#96; { | } ~
于是&#xff0c;为了解决这个问题C语言标准规定预处理器(C preprocessor)在扫描处理C语言源文件时&#xff0c;替换下述的3字符出现为1个字符&#xff1a;
三字符组替换为
也就是说&#xff0c;??/会被替换为&#xff0c;如果删掉原先的第九行&#xff0c;就变成了&#xff1a;
1 //is sqrt(30) &#43; 1 > 5 2 a&#43;&#43;;
我们都知道&#xff0c;的存在(通常一行代码太长&#xff0c;可以通过该符号来换行)&#xff0c;使得上面看似两行&#xff0c;实则是一行。即变成了&#xff1a;
1 //is sqrt(30) &#43; 1 > 5 a&#43;&#43;;
也就是说&#xff0c;a&#43;&#43;根本不会执行了&#xff0c;当然会导致最终结果不符合预期。
当然了&#xff0c;很多现代编译器可能并不会做这样的替换&#xff0c;所以这样的问题也基本无需担心&#xff0c;老实用原本的符号即可。实际上&#xff0c;细心的读者可能观察到了&#xff0c;我在前面例子代码中加了编译选项-trigraphs&#xff0c;否则的话&#xff0c;编译是有警告的&#xff1a;
1$ gcc -o main main.c2main.c: In function ‘main’:3main.c:6:27: warning: trigraph ??/ ignored, use -trigraphs to enable [-Wtrigraphs]4 //is sqrt(30) &#43; 1 > 5 ??/
双字符组
除了三字符组&#xff0c;还有双字符组。
双字符组替换为<:>]}%:#
总结
今天的你不知道很难踩坑&#xff0c;知道了也没啥用的内容就介绍到这里了。
但是留个问题&#xff1a;
为什么例子中我们使用了sqrt函数&#xff0c;但在编译时却不需要链接math库&#xff1f;答案在这里一个奇怪的链接问题
关注公众号【编程珠玑】&#xff0c;获取更多Linux/C/C&#43;&#43;/数据结构与算法/计算机基础/工具等原创技术文章。后台免费获取经典电子书和视频资源