C ,那些可愛的小陷阱(三)

2021-09-08 06:58:43 字數 1609 閱讀 3889

我們沿襲忠於標準的傳統,還是首先來看乙個標準中的例子

??=define arraycheck(a,b) a??(b??) ??!??! b??(a??)

這真是一段xe的**,你看懂什麼意思了麼?好吧這次厚道點立刻上答案:

#define arraycheck(a,b) a[b] || b[a]

這個**儘管是用來演示三元轉義符的,但是我看到這個巨集定義暗示另乙個非常古怪的語法,在沒有過載運算子的情況下,a[b]和b[a]總是完全等價的。所以在任何你使用了a[1]的時候,你都可以替換成1[a],儘管這看起來非常詭異。似乎這一點頗得標準編寫者的喜愛,居然在乙個完全無關的場合明裡暗裡地提了一下這個事情。

好吧我們言歸正傳,這些詭異的用法是c++的三元轉義符,所幸它們數量不多,請看下表:

三元符用以替代

三元符用以替代

三元符用以替代

??=#

??([

??<

??'^

??!|

??-~

注意一點我們的例子是乙個巨集定義,這很好地說明了三元轉義符是在編譯過程的最開始處理,它的優先權也是最高的,不論在任何位置(包括注釋和字串中)三元符都會被轉義。也許記憶所有轉義有些困難,但是編寫c++時注意兩個問號相連的情況就可以安全了。

關於三元轉義符有個悲情的故事,(本故事根據exceptional c++某段改編)故事講的是某粗心的軟體工程師在寫注釋的時候留了乙個問題:is it necessary?由於他想要加強語氣他決定多寫些問號,於是他按住shift和?鍵,但是很遺憾他shift鬆得早了一點,最後乙個?就變成了/(看看你的鍵盤就明白了)於是他的注釋變成了:

//is it necessary??????????????????????????????/

這看起來再正常不過了,注釋裡的文字錯誤又不會有什麼影響,然而??/卻是乙個三元符,於是轉義之後注釋變成了:

//is it necessary????????????????????????????\

到這裡想必您已經看明白了,最後乙個\成為乙個續行符,於是這行注釋吞掉了下一行**。這個問題,我目前還未發現有什麼編譯環境能夠正確地識別出來(語法著色無法反映三元轉義符),所以一旦發生,很難檢查。

悲劇版hello world:(看到沒,的**高亮也識別不出來)

#include 

<

stdio.h

>

intmain()

跟三元轉義符相似,c++裡面還有一種token替代語法,跟三元轉義符相比,它們不是純文字替換,它們自己是token的一種,可以算作對應token的別名,數量則稍微多了點:

替代的原有的替代的

原有的替代的

原有的<%

bitor

|or_eq

|=<:[or

||xor_eq

^=:>

]xor

^not!%:

#compl

~not_eq

!=:%

##bitand&

這個規則不會替換字串和注釋中的符號。

三元轉義符和token替代的存在最初都是為了某些非ansi計算機文字環境存在的,雖說到現在意義已經不是很大,但是我們程式設計的時候還是要特別注意,不要讓這些過時的語言特性變成我們**中的地雷。

C ,那些可愛的小陷阱(一)

此系列是為那些讀過tc pl或者具有類似水平的同學準備的,作為系列的第一篇以及有趣的熱身,我們來看乙個鏈結問題 d1.cpp include stdio.h struct x x x int 0,int 0 class d public x intminus inta,intb d2.cpp inc...

C ,那些可愛的小陷阱(二)

這一次,是關於宣告的乙個小問題 include stdio.h intj 24 int main 這能通過編譯嗎?能 這不會產生未定義行為嗎?不會 這程式甚至不是ill formed ill formed就是c 支援但不推薦的寫法 輸出的結果是 24 42 這個問題並不難猜到答案,但是大概大部分同學...

C ,那些可愛的小陷阱(二)

這一次,是關於宣告的乙個小問題 include stdio.h intj 24 int main 這能通過編譯嗎?能 這不會產生未定義行為嗎?不會 這程式甚至不是ill formed ill formed就是c 支援但不推薦的寫法 輸出的結果是 24 42 這個問題並不難猜到答案,但是大概大部分同學...