我在头文件中声明一个结构体。我在两个编译单元中使用这个结构。一种是使用 -std=c++11 编译的,另一种是使用 -std=c++20 编译的。我的结构体的大小在两个编译单元中是不同的。
是否允许混合任何 -std=c++20 和 -std=c++11 代码,还是我使用 GCC 的方式错误?
这些答案并不能说明它是否有效。
我在 Debian 11 (Bullseye) 上使用 GCC (Debian 10.2.1-6 (Buster)) 10.2.1 20210110。我想知道这个版本的GCC是否有bug。
演示问题的代码:
#ifndef DEF1
#define DEF1
#include "c.h"
void f1(C* c);
C* g1();
#endif
#ifndef DEF2
#define DEF2
#include "c.h"
void f2 (C* c);
C* g2();
#endif
#include "c.h"
#include <stdio.h>
void f1 (C* c)
{
printf("sizeof(C)=%ld\n", sizeof(C));
printf("i2=%d\n", c->i2);
printf("&i2-&i1=%ld\n", ((char*)&c->i2) - ((char*)&c->i1));
}
C* g1()
{
C* c = new C;
c->i2 = 1;
return c;
}
#include "c.h"
#include <stdio.h>
void f2 (C* c)
{
printf("sizeof(C)=%ld\n", sizeof(C));
printf("i2=%d\n", c->i2);
printf("&i2-&i1=%ld\n", ((char*)&c->i2) - ((char*)&c->i1));
}
C* g2()
{
C* c = new C;
c->i2 = 2;
return c;
}
#ifndef CDEF
#define CDEF
#include <stdint.h>
struct A
{
double d1{0.0};
double d2{0.0};
double d3{0.0};
double d4{0.0};
double d5{0.0};
double d6{0.0};
double d7{0.0};
int32_t i1{};
};
#ifdef DER
struct C : public A
{
int32_t i2{};
};
#else
struct C
{
double d1{0.0};
double d2{0.0};
double d3{0.0};
double d4{0.0};
double d5{0.0};
double d6{0.0};
double d7{0.0};
int32_t i1{};
int32_t i2{};
};
#endif
#endif
#include "c.h"
#include "1.h"
#include "2.h"
int main()
{
f1(g2());
f2(g1());
}
g++ -std=c++20 -DDER -c 2.cpp
g++ -std=c++11 -DDER -c 1.cpp
g++ -std=c++20 -DDER -c main.cpp
g++ -std=c++20 2.o 1.o main.o -o prog
./prog
sizeof(C)=64
i2=0
&i2-&i1=4
sizeof(C)=72
i2=0
&i2-&i1=8
是的,这是允许的,GCC 中的模错误。
GCC 遵循 Itanium ABI,尽管名称如此,它实际上是独立于平台的。以下是安腾 ABI 使命宣言:
我们希望用户能够使用不同的编译器构建可重定位对象并将它们链接在一起,如果可能的话甚至可以提供通用的 DSO。
请注意,对于不同版本的 C++ 标准,没有单独的 ABI 规范。有一种规范适用于所有这些。
这是 libstdc++ 就版本控制而言的使命宣言
扩展现有的、稳定的 ABI。版本控制使库二进制文件的后续版本能够添加新符号和功能,同时保留与该系列中先前版本的兼容性。因此,如果库二进制文件被仔细管理的后续库二进制文件替换,则与库二进制文件的初始版本链接的程序二进制文件仍将正确运行。这称为向前兼容性。
该库支持的不是一种,而是两种不同的 ABI。 C++11 标准发生了变化,需要进行 ABI 拆分。但是,正如文档所指出的,要使用的 ABI 选择独立于用于编译代码的
-std
选项。然而,这是古老的历史。您将在大约 100% 的情况下使用新的 C++11 兼容 ABI,这是默认设置,除非您需要维护使用 C++11 之前兼容的 ABI 构建的旧软件。
现实生活-std
选项。上游的每个人都使用他们想要/需要的东西,下游的库是用任何可用的选项构建的,并且毫无问题地链接在一起。一切都正常。我个人运行 Gentoo,这是一个滚动发布的发行版。我直接从该库的 GitHub 或存储的任何内容获取软件组件的任何稳定版本,并使用我当前拥有的任何编译器版本进行编译。我可以随时使用任何编译器版本重新编译任何库。系统仍然运行得很好。如果没有这种跨标准、跨版本的兼容性,滚动发布将永远没有机会发挥作用。
结论