2017-05-05 102 views
3

在使用C和C++的項目中,.h文件包含一個類型的定義。如果該定義取決於頭文件是否包含在ccpp文件中,我違反了一個定義規則嗎?預處理器分支實現的結構是否違反ODR?

// my_header.h 
struct MyStruct 
{ 
#ifdef __cplusplus 
    std::size_t member; 
    int surprise; 
#else 
    unsigned member; 
#endif 
}; 

我知道ODR有不同的翻譯單位做的,但在「我的情況」不會不同的翻譯單位最終不得不爲了一個共同的結構不同的實現?我在生產代碼中看到過這個,最初我想知道在這種情況下鏈接器是做什麼的。

有什麼想法?

+0

一點都不,只要你記得只在CPP編譯器中使用'surprise',你應該沒問題。只有其中一個條件將被編譯,因此編譯器將永遠不會看到它。 –

+0

@GillBates我正在做的項目有C和C++源文件(都使用了編譯器)。哦,那麼你的意思是說有2個連接器,所以沒有問題? –

+0

C++實際上是否在指定使用其他語言編寫程序的某些部分時會發生什麼?或者這只是未定義的? – Leushenko

回答

4

只要你使用一個編譯器(C或C++),你就不會有問題。頭文件的擴展名無關緊要。

但是,如果您將不同語言的翻譯單元連接在一起,那麼您是違反了ODR。

總的來說,這似乎很容易出錯。我會給C++類型一個完全不同的名字。你可以使用你的宏在兩者之間切換,也許使用圍繞typedef的預處理器?

+0

現在我不能做更多的抱怨我的主管,並要求10年以上的舊代碼被刪除(是的,有兩個編譯器在使用:() –

+3

@LorahAttkins:你應該提出一個重大bug在你的問題跟蹤系統,如果您認爲存在ODR違規問題,坦率地說,即使不是這樣,這是一個非常糟糕的設計並且值得一個錯誤編號,也許您的老闆決定保持原樣,或者可以爲下一個問題修復大版本 –

+1

我不認爲它違反了任何ODR,它有一個用於C的ODR和一個用於C++的ODR,它沒有違反這些ODR,它不存在用於混合C和C++項目的ODR,它只是一個區域沒有被標準覆蓋。 –

2

是的,我有一個想法(嘿,對不起,你問):請不要這樣寫代碼。好的,我會保留正確的方式來做到最後。但是,就你的問題而言:是的,如果你同時使用C和C++編譯器作爲構建過程的一部分,這將導致ODR違規。實際的文件擴展名可能不相關(它可能會改變編譯器的默認值,但是您的編譯系統可能會明確指定編譯器的語言)。也就是說,這是一個非常糟糕的想法,並且非常不尋常,因爲C離C++的真正子集非常近,所以簡單編寫也可以用C++編譯器編譯的C代碼會更加普遍。在同時擁有C和C++組件的項目中,您可以使用C++編譯器,而在純C項目中,您仍然可以使用該代碼。所以,不管文件擴展名是什麼,只要給定的項目只支持一個編譯器就沒有問題。

// my_header.h 
#ifdef __cplusplus 
    constexpr bool is_cpp = true; 
#else 
    constexpr bool is_cpp = false; 
#endif 

struct cpp { 
    std::size_t member; 
    int surprise; 
}; 

struct cc { 
    unsigned member; 
}; 

template <bool CPP> 
struct MyStructImpl : private std::conditional_t<cpp, cc, CPP> 
{ 
}; 

using MyStruct = MyStructImpl<is_cpp>; 

這使得在結構中的代碼量可能被定義以同樣的方式和無條件不管宏選項,並按照相關的東西,以儘可能晚的宏。這在工具和測試方面也是一個巨大的勝利,例如您可以在不重新編譯的情況下爲兩個版本的結構運行單元測試。

+0

我已經提到,我已經__看到這在生產代碼。從來沒有說我寫過。我已經給出了所有對我來說不好的事情:ODR,鏈接器。我以原告身份提出 –

+0

爲什麼不是一個簡單的'struct MyStruct {size_t成員,int驚喜};'用於* C和C++ *? –

+0

@LorahAttkins對不起,我當然不是故意要指責。你可以告訴你的同事和其他人,這種使用宏的條件結構是一個獨立於整個C/C++事物的壞主意。 –

3

有兩種情況:

  • 所有翻譯單元包括所述報頭(對於給定的程序)被編譯爲相同的語言(C或C++):

    ==>否問題。

  • 某些包含標題的翻譯單元被翻譯爲C,有些翻譯單元被翻譯爲C++。

    ==>違反ODR。

然而,ODR違反僅僅是「未定義的行爲」,而實際上,沒有所有在有關鏈接C和C++在一起(除了一些模糊的建議標準定義「,它應該是多少上班」)。換句話說,如果您將C和C++鏈接在一起,那麼您可能依賴於實現的細節。一般來說,如果你正在編譯32位(所以std::size_tunsigned是相同的大小),並假設C++完成所有的分配,並且假設你從不用C處理這些數組的數組,那麼你可能會逃脫它。

1

當我將多種語言連接在一起時,我不明白什麼違反了ODR? C++標準對您可以在您的目標文件中定義什麼struct沒有什麼可說的。因此,我們被迫以「彙編術語」(基於常見的實現方式)回答,在這種情況下,答案(已經得到更多雄辯)是wat

相關問題