专栏首页编程珠玑一行注释也能影响运行结果?

一行注释也能影响运行结果?

没想到吧,一行注释也能影响运行结果

也许你在某个段子里听说过,某行注释删掉后,程序竟然不能预期执行?真的会这样么?你还别不信。

见证“奇迹”

//来源:公众号【编程珠玑】
//作者:守望先生
#include <stdio.h>
#include <math.h>
int main(void)
{
    int a = (int)sqrt(30);
    //is sqrt(30) + 1 > 5 ??/
    //故意让a++,你别管为什么
    a++;
    if(a > 5)
        printf("sqrt(30) +1 > 5 \n");
    else
    {
        printf("sqrt(30) +1 <= 5 \n");
    }
    return 0;
}

编译运行:

$ gcc -o main main.c -trigraphs
$ ./main
sqrt(30) +1 > 5 

作为受过九年义务教育的我们,一看就知道结果是对的,毕竟 5 * 5 < 30 < 6 * 6。

但是删掉第九行,再运行:

$ ./main
sqrt(30) +1 <= 5 

结果竟然变了!!

看到这里,细心的读者可能已经发现了其中的端倪,我也就不卖关子了。接下来就说说我们本次要提到的主角-三字符组(trigraph sequences)。

三字符组

我们都知道C语言里面有很多转义符号,例如:

\n 换行符(LF)
\r 回车符(CR)
\t 水平制表符(HT)
\b 退格符(BS)
\’ 单引号
\” 双引号
\\ 反斜杠
......

当然还有很多,我就不一一列举了。这些符号在代码中都有特别的作用,或者无法直接输入,因此用转移符+其他字符组合来代替。

同样的,早期的一些键盘可能没法输入一些特殊的符号,如:

# $ @ [ \ ] ^ ` { | } ~ 

于是,为了解决这个问题C语言标准规定预处理器(C preprocessor)在扫描处理C语言源文件时,替换下述的3字符出现为1个字符:

三字符组

替换为

??=

#

??/

\

??'

^

??(

[

??)

]

??!

|

??<

{

??>

}

??-

~

也就是说,??/会被替换为\,如果删掉原先的第九行,就变成了:

    //is sqrt(30) + 1 > 5 \
    a++;

我们都知道,\的存在(通常一行代码太长,可以通过该符号来换行),使得上面看似两行,实则是一行。即变成了:

    //is sqrt(30) + 1 > 5 a++;

也就是说,a++根本不会执行了,当然会导致最终结果不符合预期。

当然了,很多现代编译器可能并不会做这样的替换,所以这样的问题也基本无需担心,老实用原本的符号即可。 实际上,细心的读者可能观察到了,我在前面例子代码中加了编译选项-trigraphs,否则的话,编译是有警告的:

$ gcc -o main main.c
main.c: In function ‘main’:
main.c:6:27: warning: trigraph ??/ ignored, use -trigraphs to enable [-Wtrigraphs]
     //is sqrt(30) + 1 > 5 ??/

双字符组

除了三字符组,还有双字符组。

双字符组

替换为

<:

[

:>

]

<%

{

%>

}

%:

#

总结

今天的你不知道很难踩坑,知道了也没啥用的内容就介绍到这里了。

但是留个问题:

为什么例子中我们使用了sqrt函数,但在编译时却不需要链接math库?答案在这里一个奇怪的链接问题

本文分享自微信公众号 - 编程珠玑(shouwangxiansheng),作者:守望先生

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-04-01

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 神奇,C代码竟然能当成shell脚本一样“直接”执行!

    我们都知道,写完了的C代码是需要编译链接之后才能运行的(也许你不需要手动点击编译,但是IDE可能帮你做了这件事),那么能不能让C代码像执行shell脚本或者Py...

    编程珠玑
  • 换个角度说Makefile

    作为Linux下的C/C++开发者,没接触过makefile一定说不过去,通常构建大型的C/C++项目都离不开makefile,也许你使用的是cmake或者其他...

    编程珠玑
  • 万万没想到,一个可执行文件原来包含了这么多信息!

    拿到一个编译好的可执行文件,你能获取到哪些信息?文件大小,修改时间?文件类型?除此之外呢?实际上它包含了很多信息,这些你都知道吗?

    编程珠玑
  • Laravel5.6 文件上传以及文件管理后台

    今天聊聊在Laravel5.6 如何实现文件上传功能,以及上传文件的管理功能。主要有文件列表,上传新文件,创建文件夹,删除文件夹以及删除文件。

    写PHP的老王
  • ConfigParser模块教程

    配置文件的格式与windows ini文件类似,可以包含一个或多个节(section),每个节可以有多个参数(键=值)。

    幽鸿
  • BATJ 常考的 21 条 Linux 命令

    (它用于切换当前目录,它的参数是要切换到的目录的路径,可以是绝对路径,也可以是相对路径) cd /home 进入 '/ home' 目录 cd .. ...

    挨踢小子部落阁
  • 利用Javascript做后门的利用方式

    徐焱
  • BATJ 常考的 21 条 Linux 命令

    (它用于切换当前目录,它的参数是要切换到的目录的路径,可以是绝对路径,也可以是相对路径) cd /home 进入 '/ home' 目录 cd .. ...

    lyb-geek
  • 搭建Hadoop集群

    环境说明 redhat6.7 hadoop2.7 角色 主机名 IP master node0...

    零月
  • mysql 对XA事务的支持

    MySQL 从5.0.3开始支持XA分布式事务,且只有InnoDB存储引擎支持。MySQL Connector/J 从5.0.0版本之后开始直接提供对XA的支持...

    奋斗蒙

扫码关注云+社区

领取腾讯云代金券