2017-05-05 101 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

相关问题