简体   繁体   English

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

[英]Why does the following code give different results when compiling with gcc and g++?

#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;
}

The above code gives No as output in g++ compilation and Yes in gcc compilation. 上面的代码在g++编译中给出No作为输出,在gcc编译中给出Yes Can anybody please explain the reason behind this? 任何人都能解释一下这背后的原因吗?

Your code triggers undefined behaviour because you are modifying a const object ( a ). 您的代码会触发未定义的行为,因为您正在修改const对象( a )。 It doesn't have to produce any particular result, not even on the same platform, with the same compiler. 它不必产生任何特定的结果,即使在相同的平台上,也不必使用相同的编译器。

Although the exact mechanism for this behaviour isn't specified, you may be able to figure out what is happening in your particular case by examining the assembly produced by the code (you can see that by using the -S flag.) Note that compilers are allowed to make aggressive optimizations by assuming code with well defined behaviour. 虽然没有指定此行为的确切机制,但您可以通过检查代码生成的程序集来弄清楚您的特定情况下发生了什么(您可以通过使用-S标志来查看。)请注意编译器允许通过假定具有明确定义的行为的代码来进行积极的优化。 For instance, a could simply be replaced by 1 wherever it is used. 举例来说, a可以简单地通过更换1无论在何处使用。

From the C++ Standard (1.9 Program execution) 来自C ++标准(1.9程序执行)

4 Certain other operations are described in this International Standard as undefined ( for example, the effect of attempting to modify a const object ). 4本国际标准中将某些其他操作描述为未定义( 例如,尝试修改const对象的效果 )。 [ Note: This International Standard imposes no requirements on the behavior of programs that contain undefined behavior. [注意:本国际标准对包含未定义行为的程序的行为没有要求。 —end note ] - 尾注]

Thus your program has undefined behaviour. 因此,您的程序具有未定义的行为。

In your code, notice following two lines 在您的代码中,请注意以下两行

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

you are putting the address of a const int variable to an int * and then trying to modify the value, which should have been treated as const . 您将const int变量的地址放入int * ,然后尝试修改该值,该值应该被视为const This is not allowed and invokes undefined behaviour . 这是不允许的,并调用未定义的行为

For your reference, as mentioned in chapter 6.7.3, C11 standard, paragraph 6 供参考,如第6.7.3章, C11标准第6段所述

If an attempt is made to modify an object defined with a const -qualified type through use of an lvalue with non- const -qualified type, the behavior is undefined. 如果尝试通过使用具有非const -qualified类型的左值来修改使用const -qualified类型定义的对象,则行为是未定义的。 If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined 如果尝试通过使用具有非volatile限定类型的左值来引用使用volatile限定类型定义的对象,则行为未定义

So, to cut the long story short, you cannot rely on the outputs for comaprison. 因此,长话短说,你不能依靠comaprison的输出。 They are the result of undefined behaviour. 它们是未定义行为的结果。

Okay we have here 'identical' code passed to "the same" compiler but once with a C flag and the other time with a C++ flag. 好的,我们这里的“相同”代码传递给“相同”的编译器,但一次带有C标志,另一次带有C ++标志。 As far as any reasonable user is concerned nothing has changed. 就任何合理的用户而言,没有任何改变。 The code should be interpreted identically by the compiler because nothing significant has happened. 代码应该由编译器完全相同地解释,因为没有发生任何重大事件。

Actually, that's not true. 实际上,那不是真的。 While I would be hard pressed to point to it in a standard but the precise interpretation of 'const' has slight differences between C and C++. 虽然我很难在标准中指出它,但对'const'的精确解释在C和C ++之间略有不同。 In C it's very much an add-on, the 'const' flag says that this normal variable 'a' should not be written to by the code round here. 在C中它是一个附加组件,'const'标志表示这个常规变量'a'不应该由这里的代码写入。 But there is a possibility that it will be written to elsewhere. 但它有可能被写入其他地方。 With C++ the emphasis is much more to the immutable constant concept and the compiler knows that this constant is more akin to an 'enum' that a normal variable. 对于C ++,重点更多地放在不可变常量概念上,编译器知道这个常量更类似于普通变量的“枚举”。

So I expect this slight difference means that slightly different parse trees are generated which eventually leads to different assembler. 所以我希望这种微小的差异意味着生成稍微不同的解析树,最终导致不同的汇编程序。

This sort of thing is actually fairly common, code that's in the C/C++ subset does not always compile to exactly the same assembler even with 'the same' compiler. 这种事情实际上是相当常见的,即使使用“相同的”编译器,C / C ++子集中的代码也不总是编译为完全相同的汇编程序。 It tends to be caused by other language features meaning that there are some things you can't prove about the code right now in one of the languages but it's okay in the other. 它往往是由其他语言特性引起的,这意味着有些东西你现在无法在其中一种语言中证明代码,但在另一种语言中它是可以的。

Usually C is the performance winner (as was re-discovered by the Linux kernel devs) because it's a simpler language but in this example, C++ would probably turn out faster (unless the C dev switches to a macro or enum and catches the unreasonable act of taking the address of an immutable constant). 通常C是性能优胜者(由Linux内核开发人员重新发现),因为它是一种更简单的语言,但在这个例子中,C ++可能会变得更快(除非C dev切换到宏或枚举并捕获不合理的行为)获取不可变常量的地址)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM