GCC和G ++结构包装的区别?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GCC和G ++结构包装的区别?相关的知识,希望对你有一定的参考价值。

我在我的C ++项目中使用C代码,我使用extern“C”。然后我在我的C ++类中定义了传递给C代码(使用gcc编译)的结构。问题是,当C代码访问C ++类中定义的结构时,我得到不同的对齐方式,代码读取和写入错误的数据。这看起来很奇怪,但我已经调试了3个小时,基本上当我从C ++代码打印指向该结构的深层成员时,一切都很好。但是如果我从C代码中打印指针,地址就不同了!

为什么会发生这种情况,如何确保我的对齐方式一致?

(我通过重新编译所有内容来仔细检查这不是过时的编译问题。仍然是相同的结果。在C中,地址是在C ++代码中报告的成员地址之前的8个字节)

编辑:问题是g ++和gcc会以不同的方式处理空结构。如果我的代码中有一个空的struct foo {},那么我的结构的sizeof在g ++下会大1个字节,并且所有成员的偏移都会搞砸。所以我把一个虚拟uint8_t放到空结构中,这样它就不再是空的了,代码库中的所有这些问题似乎都消失了。现在对齐似乎工作原理相同,结构大小也相同(对于每个空结构,g ++以前会添加1个字节)。我不是100%确定gcc会发生什么,所以如果有人有什么需要添加的话请随时填写我

我的gcc版本是:

Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 5.4.0-6ubuntu1~16.04.5' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-5 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 5.4.0 20160609

我在gcc下的编译标志是:

-std=gnu99 -Wchar-subscripts -Wformat -Wformat-nonliteral -Wformat-security -Wmissing-braces -Wparentheses -Wsequence-point -Wswitch -Wtrigraphs -Wno-unused-function -Wunused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wuninitialized -Wdiv-by-zero -Wfloat-equal -Wdouble-promotion -fsingle-precis
ion-constant -Wshadow -Wpointer-arith -Wwrite-strings -Wconversion -Wredundant-decls -Wunreachable-code -Winline -Wenum-compare -Wlong-long -Wchar-subscripts -Wextra -Werror -g -Os -ffunction-sections -fdata-sections -m32 -fstack-protector -D_XOPEN_SOURCE=700 -D_GNU_SOURCE -ftest-coverage -fprofile-arcs

克++

-std=c++11 -Wextra -Werror -g -Os -ffunction-sections -fdata-sections -m32 -fstack-protector -D_XOPEN_SOURCE=700 -D_GNU_SOURCE -ftest-coverage -fprofile-arcs

Edit2:为我的C标志添加了-pedantic,使gcc警告空结构。以前删除它因为它打破了许多其他东西和第三方标题(我们必须使用-Werror)。幸运的是,宏({})语句之类的内容可以使用__extension__作为前缀,以使它们成为通过函数。还有一些需要在代码库中更改的东西。不知道是否有一些难以实现的迂腐功能。有谁知道如何只为空结构启用警告或禁用一些迂腐不允许的特定事物?

答案

正确的解决方案似乎是永远不要在将跨C ++ - > C边界使用的代码中定义空结构。我曾有一个:

struct spinlock { } 

在针对单个处理器目标构建时是空的。所以g ++会使这个1字节,而gcc只会丢弃它。因此,我的结构将是不同的大小,offset甚至会返回不同的结果,具体取决于代码是使用gcc还是g ++构建的。

所以我改成了

struct spinlock { uint8_t dummy; }

现在我的结构完美对齐,一切正常,没有任何特殊的C ++标准规范。

另一答案

空结构可以为您提供一些实现定义或非标准行为。首先,标准C不支持空结构.GCC支持将它们作为大小== 0的扩展。

C ++支持空结构,但要求它们在用作“最派生对象”时具有非零大小。但是,C ++还允许从空结构继承的类/结构为子类优化该大小。

以上是关于GCC和G ++结构包装的区别?的主要内容,如果未能解决你的问题,请参考以下文章

由于用于构建 GCC 的 CPU 的体系结构,这是 g++ 的“非法指令错误”吗?

SWT和Swing代码的区别

C语言编译器icc与gcc编译出来的执行文件有啥区别?

gcc:自定义部分中的单独代码和数据

C语言和其他高级语言的最大的区别是啥

linux 生成的.o文件为啥带锁标志