是否可以强制(比如“gcc”)为C和C++中相同的源代码生成相同的二进制文件

Is it possible to force say, `gcc`, to produce identical binaries for identical pieces of source code in C and C++?

本文关键字:C++ 二进制文件 代码生成 比如 gcc 是否      更新时间:2023-10-16

假设有一个C程序,如下所示:

int main(int argc, char** argv)
{
    return 0;
}

我有两个以上源代码的文件,一个扩展名为"c",另一个扩展名称为"cpp"。我将它们分别编译为C和C++程序二进制文件不同。我认为C++是一种"零开销"语言?:-)我试图找到的是两种不同设置的编译器标志,其中生成的二进制文件是相同的。最好是某种语言标准,而不是任何类型的GCC扩展。

二进制文件不同

它们有何不同?

GCC将在文件中嵌入有关原始源文件名和所用选项的信息,因此对于不同的文件名,即使内容相同,也总是会有一些差异。

如果我将您的程序编译为C和C++,我看到的唯一区别是C++版本链接到libstdc++,这在使用g++进行链接时会自动发生。如果我使用gcc来链接,那么二进制文件几乎是相同的。

注意:您可以使用gcc编译C++程序,gccg++二进制文件只是查看文件名并调用正确的编译器二进制文件(cc1用于C,cc1plus用于C++)进行实际编译的驱动程序。看见http://gcc.gnu.org/onlinedocs/gcc/Invoking-G_002b_002b.html了解更多详细信息。

这表明,对于相同的源代码,汇编程序输出的唯一区别是给出原始文件名的字符串,而目标文件的大小相同:

$ cat f.c
cat: f.c: No such file or directory
$ rm f.c
$ cat > f.c
int main(int argc, char** argv)
{
    return 0;
}
$ ln -s f.c f.cc
$ gcc f.c -S -o f.c.s
$ g++ f.cc -S -o f.cxx.s
$ diff f.c*.s
--- f.c.s       2012-08-26 13:45:58.109711329 +0100
+++ f.cxx.s     2012-08-26 13:46:00.482634256 +0100
@@ -1,4 +1,4 @@
-       .file   "f.c"
+       .file   "f.cc"
        .text
        .globl  main
        .type   main, @function
$ gcc f.c -c -o f.c.o
$ g++ f.cc -c -o f.cxx.o
$ ls -l f.c*.o
-rw-rw-r--. 1 jwakely users 1240 Aug 26 13:46 f.c.o
-rw-rw-r--. 1 jwakely users 1240 Aug 26 13:46 f.cxx.o

在最终的可执行文件中,差异来自于它的链接方式,无论C++标准库是否链接到:

$ gcc f.c.o -o a.c.out
$ gcc f.cxx.o -o a.cxx.out
$ g++ f.cxx.o -o a.cxx.libstdcxx.out
$ ls -l a.c*.out
-rwxrwxr-x. 1 jwakely users 6323 Aug 26 13:48 a.c.out
-rwxrwxr-x. 1 jwakely users 6468 Aug 26 13:48 a.cxx.libstdcxx.out
-rwxrwxr-x. 1 jwakely users 6324 Aug 26 13:48 a.cxx.out

如果您不需要C++标准库,请不要链接到它。

这只是"我的空main有多短"错误问题的另一个版本。

"基础设施"的一部分携带启动和结束代码,以及在任何情况下都必须链接的标准库全局对象,无论程序实际是什么

测量一个空的主程序,实际上就是测量启动/结束代码的大小。这在C和C++中肯定是不同的,因为C++要做的准备调用main的事情比C实际要做的多得多

我不知道你说的"零开销语言"是什么意思。C和C++都不是。它们都将各自域中的开销降至最低。根据定义,唯一的零开销语言是本机代码。

当然它们是不同的,即使是像函数名这样简单的东西,c和c++也会有不同的处理方式。c中的void foo()就是c++中的foo,因为c版本没有包含足够的信息来处理具有不同参数列表(如void foo(int))的多个foo函数,所以这个名称会被破坏。

然后有不同的标准库,它们在默认情况下被链接进来,因为它们被大多数c/c++程序使用(对于零开销声明,这可以被禁用)。

最重要的是关于定义良好的行为的不同规则,c++不是c的超集,虽然有大量的重叠,但在许多情况下它们是不同的。请参见c和c++中的示例sizeof('a')

结论:c和c++编译器在可能的情况下从相同的源代码中生成相同的二进制文件是极不可能发生的。