C++ 如何找出gcc和g++;产生不同的代码

C++ 如何找出gcc和g++;产生不同的代码,c++,c,gcc,compiler-construction,C++,C,Gcc,Compiler Construction,是否有可能看到gcc和g++编译过程背后发生了什么 我有以下计划: #include <stdio.h> #include <unistd.h> size_t sym1 = 100; size_t *addr = &sym1; size_t *arr = (size_t*)((size_t)&arr + (size_t)&addr); int main (int argc, char **argv) { (void) argc;

是否有可能看到gcc和g++编译过程背后发生了什么 我有以下计划:

#include <stdio.h>
#include <unistd.h>

size_t sym1 = 100;
size_t *addr = &sym1;

size_t *arr = (size_t*)((size_t)&arr + (size_t)&addr);

int main (int argc, char **argv)
{
    (void) argc;
    (void) argv;

    printf("libtest: addr of main(): %p\n", &main);
    printf("libtest: addr of arr: %p\n", &arr);

    while(1);
    return 0;
}
我认为原因可能是gcc使用cc1作为编译器,而g++使用cc1plus。
有没有一种方法可以更精确地输出实际完成的工作?
我尝试使用-v标志,但输出非常相似。是否有不同的标志传递给链接器?

比较两个编译过程并找出其差异的最简单方法是什么

在这种情况下,
gcc
不会产生任何结果,因为您的程序不是有效的C。正如编译器所解释的,初始化器元素(用于初始化全局变量
arr
的表达式)不是常量

C要求初始化表达式是编译时常量,以便本地变量的内容可以放在可执行文件的数据段中。这不能用于
arr
,因为相关变量的地址在链接时间之前是未知的,动态链接器不能简单地填写它们的总和,就像
addr1
的情况一样。C++允许这样做,所以<代码> G++< /CODE>生成初始化代码,这些代码用于评估非常量表达式并将它们存储在全局变量中。此代码在调用
main()
之前执行


可执行文件
cc1
cc1plus
是编译器实现的内部细节,因此与观察到的行为无关。相关的事实是,<代码> GCC 希望有效的C代码作为输入,<代码> G++< /Cord>期望有效的C++代码。您提供的代码是有效的C++,但不是有效的C,这就是为什么代码> G++< /COD>编译它和<代码> GCC 不。

< P>这里有一个稍微有趣的问题。考虑以下测试用例:

#include <stdint.h>

#if TEST==1
void *p=(void *)(unsigned short)&p;
#elif TEST==2
void *p=(void *)(uintptr_t)&p;
#elif TEST==3
void *p=(void *)(1*(uintptr_t)&p);
#elif TEST==4
void *p=(void *)(2*(uintptr_t)&p);
#endif
#包括
#如果测试==1
void*p=(void*)(无符号短线)和p;
#elif测试==2
void*p=(void*)(uintptr\t)和p;
#elif检验==3
无效*p=(无效*)(1*(无效*)&p);
#elif测试==4
无效*p=(无效*)(2*(无效*)&p);
#恩迪夫
gcc(即使使用非常保守的标志
-ansi-pedantic errors
)拒绝测试1但接受测试2,接受测试3但拒绝测试4

由此我得出结论,在检查初始值设定项是否为常量表达式之前,一些容易优化的操作(如对相同大小的对象进行强制转换或乘以1)会被消除


因此,根据C标准,gcc可能会接受一些它应该拒绝的东西。但是,当您使它们稍微复杂一些时(比如将一个强制转换的结果添加到另一个强制转换的结果中——添加两个地址可能会产生什么有用的值?),它会注意到问题并拒绝表达式。

因为
C=其中一个原因是它们链接到不同的库。因为GCC编译C代码和C++编译C++代码,这些代码是相似但仍然不同的语言。我不是一个专家,但我的猜测是,你在那里尝试过的事情(将一个非常量分配给一个全局变量)在c中根本不可能。请看主题中的实际问题(不仅仅是标题):-)我想知道一些方法来输出编译过程中发生的事情。使用了哪些子程序,传递给它们的标志是什么,链接了哪些库。。。我想了解一些背景…@MikhailKalashnikov自2011年起将-v标志添加到gcc或g++中它也无效
C++
,因为
while(1).Ah,但最好说明为什么初始值设定项表达式不是常量表达式,这是因为相关的地址直到链接时才知道。在C++中,我相信编译器输出的量是一个小型构造函数。(不完全是构造函数,但通常使用构造函数机制来运行。)但是为什么“addr”变量没有错误呢?“sym1”的地址也要到链接时间才能知道,不是吗?为什么gcc可以编译“intaddr=&sym1”,但不能编译“intaddr=&sym1+&sym2”?(为什么g++可以同时编译这两个?@MikhailKalashnikov最后一个问题的答案是,编译器必须将指令放入对象文件中,以便链接器在链接时将正确的地址放入正确的位置。这些指令(称为重定位)的格式非常简单,可能无法进行加法。(顺便说一句,我使用了一般意义上的“指令”,与“CPU架构的指令”无关)@user4815162342:BTW,我在C99中发现了另一个相关位,这使得OP中的表达式在6.6第6段中是非法的:整型常量表达式应为整型,且只能包含整型常量、枚举常量、字符常量、结果为整型常量的
sizeof
表达式的操作数,以及作为强制转换直接操作数的浮点常量。整数常量表达式中的强制转换运算符只能将算术类型转换为整数类型,除非作为操作数的一部分转换为
sizeof
运算符。”
#include <stdint.h>

#if TEST==1
void *p=(void *)(unsigned short)&p;
#elif TEST==2
void *p=(void *)(uintptr_t)&p;
#elif TEST==3
void *p=(void *)(1*(uintptr_t)&p);
#elif TEST==4
void *p=(void *)(2*(uintptr_t)&p);
#endif