C++ 链接C+是否安全+;17,C++;14和C++;11个对象

C++ 链接C+是否安全+;17,C++;14和C++;11个对象,c++,c++11,linker,c++14,abi,C++,C++11,Linker,C++14,Abi,假设我有三个编译对象,它们都由相同的编译器/版本生成: A是用C++11标准编译的 B是用C++14标准编译的 C是用C++17标准编译的 为了简单起见,我们假设所有的头都是用C++11编写的,只使用语义在所有三个标准版本之间没有改变的结构,因此任何依赖关系都是通过头包含正确表达的,编译器没有反对 链接到一个二进制文件中,这些对象的哪些组合是安全的?为什么? 编辑:主要编译器(例如GCC、CLAN、VS++)的答案是受欢迎的< /P> < P>新的C++标准分为两部分:语言特征和标准库组件。

假设我有三个编译对象,它们都由相同的编译器/版本生成:

  • A是用C++11标准编译的
  • B是用C++14标准编译的
  • C是用C++17标准编译的
  • 为了简单起见,我们假设所有的头都是用C++11编写的,只使用语义在所有三个标准版本之间没有改变的结构,因此任何依赖关系都是通过头包含正确表达的,编译器没有反对

    链接到一个二进制文件中,这些对象的哪些组合是安全的?为什么?



    <>编辑:主要编译器(例如GCC、CLAN、VS++)的答案是受欢迎的< /P> < P>新的C++标准分为两部分:语言特征和标准库组件。 正如您所说的新标准,语言本身的更改(例如,Range for)几乎没有问题(有时第三方库标题与较新的标准语言功能之间存在冲突)

    但是标准图书馆

    <>每个编译器版本都带有C++标准库(LIGBSTD++ + GCC,LCBC+ + CLAN,MSC++ C++标准库,VC++),以及一个实现,每个标准版本的实现不多。此外,在某些情况下,您可能会使用编译器提供的标准库以外的其他实现。您应该关心的是将旧的标准库实现与新的标准库实现链接起来


    第三方库和代码之间可能发生的冲突是链接到该第三方库的标准库(和其他库)。

    答案有两部分。编译器级别的兼容性和链接器级别的兼容性。让我们从前者开始

    假设所有的头都是用C++11编写的

    使用相同的编译器意味着,无论目标C++标准如何,都使用相同的标准库头和源文件(与编译器相关的ONCES)。因此,标准库的头文件被编写为与编译器支持的所有C++版本兼容。 < P >,如果编译一个翻译单元的编译器选项指定了一个特定的C++标准,那么任何只能在新标准中可用的特征都是不可访问的。这是使用

    \uuu cplusplus
    指令完成的。请参阅源文件,了解如何使用它的有趣示例。类似地,编译器将拒绝新版本标准提供的任何语法特性

    所有这些都意味着您的假设只能应用于您编写的头文件。当包含在不同C++程序的不同翻译单元中时,这些头文件可能导致不兼容。这是在C++标准附件C中讨论的。共有4条条款,我只讨论第一条,并简要提及其余条款

    C.3.1第2条:词汇约定

    单引号在C++11中分隔字符文字,而在C++14和C++17中它们是数字分隔符。假设在纯C++11头文件之一中有以下宏定义:

    #define M(x, ...) __VA_ARGS__
    
    // Maybe defined as a field in a template or a type.
    int x[2] = { M(1'2,3'4) };
    
    考虑包含头文件的两个翻译单元,但分别以C++11和C++14为目标。以C++11为目标时,引号内的逗号不被视为参数分隔符;只有一个参数。因此,该准则相当于:

    int x[2] = { 0 }; // C++11
    
    int x[2] = { 34, 0 }; // C++14 and C++17
    
    另一方面,当以C++14为目标时,单引号被解释为数字分隔符。因此,该准则相当于:

    int x[2] = { 0 }; // C++11
    
    int x[2] = { 34, 0 }; // C++14 and C++17
    
    这里的要点是,在一个纯C++11头文件中使用单引号可能会导致针对C++14/17的翻译单元出现令人惊讶的错误。因此,即使头文件是用C++11编写的,也必须仔细编写,以确保它与标准的更高版本兼容。
    \uuu cplusplus
    指令在这里可能很有用

    本标准的其他三个条款包括:

    C.3.2第3条:基本概念

    更改:新的常用(非配售)解除定位器

    基本原理:按大小分配所需

    对原始功能的影响:有效的C++2011代码可以声明全局放置分配函数和释放函数,如下所示:

    void operator new(std::size_t, std::size_t); 
    void operator delete(void*, std::size_t) noexcept;
    
    然而,在本国际标准中,运营商的声明 delete可能与预定义的常用(非放置)运算符delete匹配 (3.7.4). 如果是这样的话,程序的格式是错误的,就像对类成员一样 分配函数和解除分配函数(5.3.4)

    C.3.3第7条:声明

    更改:constexpr非静态成员函数不是隐式常量 成员职能

    基本原理:允许constexpr成员函数变异 反对

    对原始功能的影响:有效的C++2011代码可能无法在此环境中编译 国际标准

    例如,以下代码在C++2011中有效,但在中无效 这是国际标准,因为它声明了相同的成员 使用不同的返回类型执行两次函数:

    struct S {
    constexpr const int &f();
    int &f();
    };
    
    C.3.4第27条:输入/输出库

    更改:未定义获取

    理由:使用GET被认为是危险的

    对原始功能的影响:使用get的有效C++2011代码 函数可能无法在本国际标准中编译

    C.4中讨论了C++14和C++17之间的潜在不兼容性。由于所有非标准头文件都是用C++11编写的(如问题中所述),因此不会出现这些问题,因此我在这里不再提及它们

    现在我将讨论链接器级别的兼容性。一般来说,incom的潜在原因