具有预处理器分支实现的结构是否违反ODR? 在使用C和C++的项目中,代码> h < /C>文件包含类型的定义。如果该定义取决于头是否包含在c或cpp文件中,那么我是否违反了一个定义规则 // my_header.h struct MyStruct { #ifdef __cplusplus std::size_t member; int surprise; #else unsigned member; #endif };

具有预处理器分支实现的结构是否违反ODR? 在使用C和C++的项目中,代码> h < /C>文件包含类型的定义。如果该定义取决于头是否包含在c或cpp文件中,那么我是否违反了一个定义规则 // my_header.h struct MyStruct { #ifdef __cplusplus std::size_t member; int surprise; #else unsigned member; #endif };,c++,c,struct,one-definition-rule,C++,C,Struct,One Definition Rule,我知道ODR与不同的翻译单元有关,但在“我的情况”中,不同的翻译单元对于一个公共结构不会有不同的实现吗?我在生产代码中看到了这一点,最初我想知道链接器在这种情况下做了什么 有什么想法吗?是的,我有一个想法(嘿,对不起,你问了):请不要那样写代码。好的,我会保留正确的方法直到最后。但就你的问题而言:是的,如果你同时使用C和C++编译器作为构建过程的一部分,这将导致ODR违规。实际的文件扩展名可能与此无关(它可能会更改编译器的默认值,但生成系统可能会显式指定编译器使用的语言)。也就是说,这是一个非常

我知道ODR与不同的翻译单元有关,但在“我的情况”中,不同的翻译单元对于一个公共结构不会有不同的实现吗?我在生产代码中看到了这一点,最初我想知道链接器在这种情况下做了什么

有什么想法吗?

是的,我有一个想法(嘿,对不起,你问了):请不要那样写代码。好的,我会保留正确的方法直到最后。但就你的问题而言:是的,如果你同时使用C和C++编译器作为构建过程的一部分,这将导致ODR违规。实际的文件扩展名可能与此无关(它可能会更改编译器的默认值,但生成系统可能会显式指定编译器使用的语言)。也就是说,这是一个非常糟糕的想法,而且非常不寻常,因为C非常接近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>;
//my_header.h
#ifdef_uucplusplus
constexpr bool是_cpp=true;
#否则
constexpr bool是_cpp=false;
#恩迪夫
结构cpp{
std::尺寸\u t成员;
意外;
};
结构cc{
未签署成员;
};
模板
struct MyStructImpl:private std::conditional\u t
{
};
使用MyStruct=MyStructImpl;

这将尽可能多的代码保留在以相同方式无条件定义的结构中,而不考虑宏选项,并将与宏相关的内容尽可能延迟。这在工具和测试方面也是一个巨大的胜利,例如,您可以在不重新编译的情况下为两个版本的结构运行单元测试。

只要您使用一个编译器(C或C++),就不会有问题。头文件的扩展名是什么并不重要

但是如果你把不同语言的翻译单元连接在一起,那么你违反了ODR

总的来说,这看起来很容易出错。我会给C++类型一个完全不同的名字。您可以使用宏在这两种情况之间切换,也许可以使用预处理器围绕
typedef

有两种情况:

  • 包含标题的所有翻译单元(对于给定程序)都编译为相同的语言(C或C++):

    =>没问题

  • >P>包括头的一些翻译单元被翻译成C,有些被翻译成C++。 ==>ODR冲突

然而,ODR违规只是“未定义的行为”,实际上,在C和C++的链接标准中没有什么定义(除了一些模糊的建议“应该工作”)。换句话说,如果你将C和C++链接在一起,那么你可能还是依赖于你的实现的细节。

一般来说,如果你编译的是32位(因此<代码> STD::SigZiT<< /Cord>和UnSt签名)是相同的,并且提供C++做所有的分配,并且提供在C中从不处理这些东西的数组,您可能会侥幸逃脱。

我不清楚当您将多种语言链接在一起时,违反ODR意味着什么;C++标准没有什么可以说明在C对象文件中定义的 Stutt s。因此,我们不得不用“汇编术语”(基于常见实现)来回答,在这种情况下,答案(已经给出了更为有力的答案)是wat

一点也不,只要您记住在CPP编译器中只使用
惊奇
,您就可以了。只有一个条件编译,编译器永远不会看到它。@吉尔巴茨我正在做的项目既有C和C++源文件(也使用编译器)。哦,那你是说有2个链接器,所以没有PROB?C++是否真的关心指定你的程序的一部分是用另一种语言编写时会发生什么?或者这只是没有定义?这看起来像是违反常识。为什么你要在同一个名字后面隐藏不同的东西?@LorahAttkins不,那很可能是一个链接器。您的问题是完全正确的,我恐怕答案是“是的,这是一个问题”。我已经提到,我在生产代码中看到了这一点。从来没说过是我写的。我已经发布了所有对我来说不好的东西:ODR,链接器。作为原告,我在问为什么不是一个简单的
struct MyStruct{size\u t member,int should}