vlambda博客
学习文章列表

10行C语言代码却搞了我一个通宵!写了5年代码我居然还没搞懂switch语句!


直接上代码!


test.c

#include <stdio.h>
int main(){ int a = 1;
// a > 1 ??/ a++;
if (a > 1) { printf("a > 1\n"); } else { printf("a <= 1\n"); }
return 0;}


多么简单的代码,结果是啥?

肯定输出:a > 1

下面我们来编译一下:


gcc test.c -o test


10行C语言代码却搞了我一个通宵!写了5年代码我居然还没搞懂switch语句!


编译出现了警告!不过没关系,根据提示,可以通过 -trigraphs 选项消除警告。重新编译:


gcc test.c -o test -trigraphs


运行看下结果:


10行C语言代码却搞了我一个通宵!写了5年代码我居然还没搞懂switch语句!


什么?结果怎么会是 a <= 1


再来看一个问题!


test.c

#include <stdio.h>
int calculator(int x, int y, char opt){ switch(opt) { case '+': return x + y; case '-': return x - y; case '*': return x * y;        defualt: return x / y; } }
int main(){ int a = 2, b = 1;
printf("%d\n", calculator(a, b, '/'));
return 0;}


编译:


gcc test.c -o test


运行:


10行C语言代码却搞了我一个通宵!写了5年代码我居然还没搞懂switch语句!


2 / 1 等于 47 是什么鬼!


当然这两个代码都是我从项目中单独拿出来写的demo,如果把它们放在一大堆代码中,又得搞个通宵了。



三字符组


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


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


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


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


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


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


??=      替换为 #??/      替换为 \??`      替换为 ^??(      替换为 [??)      替换为)??!      替换为|??< 替换为{??>      替换为}??- 替换为~



也就是说,“??/”会被替换为“\”!


那么问题就清晰了。“\”在C语言中用作连接两行代码,也就是对编译器来说,第 7 行和第 8 行被当作成 1 行代码,“a++”属于注释语句,并没有执行。


当然了,很多现代编译器可能并不会做这样的替换,所以这样的问题也基本无需担心,老实用原本的符号即可。而且就算是替换了,也会在编译的时候报出警告。



default


首先,case 和 default 都是C语言的关键字。


无论把 default 写成什么,都能编译成功。


只是程序执行的时候,不会进入这个分支!


编译器把错写的标识当成了标签,因为一行中冒号之前都被当作标签。


它可以是任意标识。


所以,default误写不会导致编译错误,但是却导致了执行错误。



10行C语言代码却搞了我一个通宵!写了5年代码我居然还没搞懂switch语句!


又是一个心力憔悴的夜晚。不说了,赶紧睡觉!


10行C语言代码却搞了我一个通宵!写了5年代码我居然还没搞懂switch语句!

10行C语言代码却搞了我一个通宵!写了5年代码我居然还没搞懂switch语句!


10行C语言代码却搞了我一个通宵!写了5年代码我居然还没搞懂switch语句!


10行C语言代码却搞了我一个通宵!写了5年代码我居然还没搞懂switch语句!


10行C语言代码却搞了我一个通宵!写了5年代码我居然还没搞懂switch语句!