为什么在使用gcc和g ++编译时,以下代码会给出不同的结果?

时间:2015-03-26 06:47:35

标签: c gcc g++ const

#include<stdio.h>
int main()
{
    const int a=1;
    int *p=(int *)&a;
    (*p)++;
    printf("%d %d\n",*p,a);
    if(a==1)
      printf("No\n");//"No" in g++.
    else
      printf("Yes\n");//"Yes" in gcc.
    return 0;
}

上面的代码在No编译中提供了g++作为Yes汇编中的gcc。有人可以解释一下这背后的原因吗?

4 个答案:

答案 0 :(得分:10)

您的代码会触发未定义的行为,因为您正在修改const对象(a)。它不必产生任何特定的结果,即使在相同的平台上,也不必使用相同的编译器。

虽然没有指定此行为的确切机制,但您可以通过检查代码生成的程序集来弄清楚您的特定情况发生了什么(您可以通过使用{{1注意,允许编译器通过假设代码具有良好定义的行为来进行积极的优化。例如,-S可以简单地用a替换,只要它被使用。

答案 1 :(得分:6)

来自C ++标准(1.9程序执行)

  

4本国际上描述了某些其他操作   标准为未定义(例如,尝试的效果   修改const对象)。 [注:本国际标准规定   对包含undefined的程序的行为没有要求   行为。 - 后注]

因此,您的程序有不确定的行为。

答案 2 :(得分:4)

在您的代码中,请注意以下两行

const int a=1;        // a is of type constant int
int *p=(int *)&a;     // p is of type int *

您要将const int变量的地址添加到int *,然后尝试修改该值,该值应该被视为const。这是不允许的,并调用undefined behaviour

如第6.7.3章C11标准第6段

所述,供您参考
  

如果尝试通过使用修改使用const限定类型定义的对象   对于具有非const - 限定类型的左值,行为未定义。如果尝试是   通过使用左值来引用用volatile限定类型定义的对象   对于非volatile限定类型,行为未定义

因此,长话短说,你不能依靠comaprison的输出。它们是未定义行为的结果。

答案 3 :(得分:1)

好的,我们这里有相同的&#39;代码传递给&#34;同样的&#34;编译但一次 带有C标志,另一次带有C ++标志。至于任何合理的 用户担心一切都没有改变。代码应该被解释 由编译器完全相同,因为没有发生任何重大事件。

实际上,这不是真的。虽然我很难指出它 一个标准,但准确的解释&#39; const&#39;有轻微的差异 在C和C ++之间。在C中它是一个附加组件,&#39; const&#39;旗 说这个正常变量&#39; a&#39;不应该由代码写入 在这里。但它有可能被写入 别处。对于C ++,重点更多的是不可变常量 概念和编译器都知道这个常量更像是一个 &#39;枚举&#39;这是一个正常变量。

所以我希望这个微小的差异意味着稍微不同的解析 生成的树最终导致不同的汇编程序。

这类事实上很常见,C / C ++中的代码 即使使用子集,子集也不总是编译到完全相同的汇编程序 &#39;相同&#39;编译器。它往往是由其他语言功能引起的 这意味着有些事情你可以证明代码是正确的 现在用其中一种语言,但在另一种语言中没问题。

通常C是性能优胜者(正如Linux重新发现的那样) kernel devs)因为它是一种更简单的语言,但在本例中是C ++ 可能会更快(除非C dev切换到宏 或者枚举 并抓住了取不变量常数的不合理行为。)