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

2021-07-09 03:46:42 字數 1599 閱讀 7308

此系列是為那些讀過tc++pl或者具有類似水平的同學準備的,作為系列的第一篇以及有趣的熱身,我們來看乙個鏈結問題:

d1.cpp

#include 

<

stdio.h

>

struct

x ;x::x(

int=0, 

int=0) 

class

d: public

x ; 

intminus(

inta,

intb)

d2.cpp 

#include 

<

stdio.h

>

struct

x ;x::x(

int=0) 

class

d: public

x ;int

add(

inta,

intb)

用來執行的main.cpp:

#include 

<

stdio.h

>

intminus(

inta,

intb);

intadd(

inta,

intb);

intmain()

將以上三個cpp檔案分別編譯並鏈結成乙個應用程式,在執行之前,請先猜個結果。然後執行。

好吧,我想你看到了答案。在你開始思考為什麼會是這樣的之前,請再做一件事,將d1.cpp和d2.cpp兩個檔案的內容完全交換,然後重新編譯執行一次。

請原諒上面寫的比較混亂且沒有給出每一步的結果,因為使用vs的c++編譯器,這個結果是不確定的。然而毫無疑問,兩次執行的結果將是不同的!

在我這裡,第一次顯示了22

第二次顯示了11

omg,檔案居然影響了程式結果!所以請不要總是相信編譯器,這個例子來自c++標準,它用以說明乙個重要的準則:one defination rule,簡寫odr

odr在c++標準中被解釋為:

1.任何編譯單元都不能包含變數、函式、列舉、類或者模板的定義一次以上。

2.所有程式必須且只能包含一次其中用到的所有非內聯函式和物件。

3.在需要類的完整定義的編譯單元中,類的定義必須且只能出現一次。

4.(好bt的一條啊,恰好這一條可以解釋我們的程式)包括類、列舉、類模板......(具體有哪些請自己看spec)在內的一些定義可以在乙個程式中出現多次,但是必須滿足以下條件:

(1)所有定義的token序列必須相同(token你可以認為就是有效的語言要素,出了空白、換行注釋之類的)

(2)所有的命名查詢必須指向同乙個實體,也就是說,你不能搞一些命名空間 typedef之類的,讓這些相同的token表示不同的意義

(3)所有運算子必須表示同乙個過載

(4)對於你要定義的實體中的所有帶預設引數的函式,預設引數必須滿足以上三條

(5)對於類定義,建構函式中呼叫的基類建構函式必須是同乙個

總而言之,這個第四條的意思就是不同的定義之間不能有任何歧義

ps.g++似乎做了跟vc++相同的事情,表現基本一致。

from:

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

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

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

我們沿襲忠於標準的傳統,還是首先來看乙個標準中的例子 define arraycheck a,b a?b?b?a?這真是一段xe的 你看懂什麼意思了麼?好吧這次厚道點立刻上答案 define arraycheck a,b a b b a 這個 儘管是用來演示三元轉義符的,但是我看到這個巨集定義暗示另...

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

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