一行注釋也能影響運行結果?

沒想到吧,一行注釋也能影響運行結果

也許你在某個段子里聽說過,某行注釋刪掉後,程式竟然不能預期執行?真的會這樣么?你還別不信。

見證「奇蹟」

//來源:公眾號【編程珠璣】  //作者:守望先生  #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庫?答案在這裡一個奇怪的鏈接問題