3
#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. Can anybody please explain the reason behind this?

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • Are you asking "Why is this allowed to happen?" or "I know anything is allowed to happen, but what mechanism inside the compiler makes *this particular* thing happen?"? – user253751 Mar 26 '15 at 06:54
  • @immibis I guess the later one "I know anything is allowed to happen, but what mechanism inside the compiler makes this particular thing happen?" – Rohit Chauhan Mar 26 '15 at 06:58
  • @RohitChauhan , read the answers. – Arun A S Mar 26 '15 at 07:00
  • @ArunA.S The answers answer the first meaning of the question, not the second. – user253751 Mar 26 '15 at 07:01
  • What do you want to possibly achieve with this code? – Mohit Jain Mar 26 '15 at 07:03
  • If you want an answer to the second meaning, it might be worth asking the question again, but adding that you already know it's undefined behaviour, and you want to know how the compiler internally arrives at this result. (But who knows how Stack Overflow works). Obviously, only do that if you're interested in the internals of compilers, not just in writing C or C++ programs. – user253751 Mar 26 '15 at 07:03
  • @RohitChauhan , How do you expect us to know how the compiler does that. You would have to ask the person who programmed the compiler. This is not defined in the c or c++ standard, so it depends on the compiler and how it optimizes this. – Arun A S Mar 26 '15 at 07:03
  • possible duplicate of [newbie question: c++ const to non-const conversion](http://stackoverflow.com/questions/7311041/newbie-question-c-const-to-non-const-conversion) – Mohit Jain Mar 26 '15 at 07:05
  • 1
    Which versions of `g++` and `gcc` are you using? Also, what command line options did you use to compile the code? I expect that `g++` is replacing `a` with the literal constant `1` in the `if`, but `gcc` is not. – clstrfsck Mar 26 '15 at 07:27
  • 1
    @MohitJain not really – M.M Mar 26 '15 at 07:48
  • Another similar one would be [changing the value of const variable in C++](http://stackoverflow.com/questions/2006161/changing-the-value-of-const-variable-in-c). SO is full of similar question. – Mohit Jain Mar 26 '15 at 08:17

4 Answers4

10

Your code triggers undefined behaviour because you are modifying a const object (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. For instance, a could simply be replaced by 1 wherever it is used.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
6

From the C++ Standard (1.9 Program execution)

4 Certain other operations are described in this International Standard as undefined (for example, the effect of attempting to modify a const object). [ Note: This International Standard imposes no requirements on the behavior of programs that contain undefined behavior. —end note ]

Thus your program has undefined behaviour.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
4

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. This is not allowed and invokes undefined behaviour.

For your reference, as mentioned in chapter 6.7.3, C11 standard, paragraph 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. 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

So, to cut the long story short, you cannot rely on the outputs for comaprison. They are the result of undefined behaviour.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • Do you know when this made it into C ? Because it changes the definition of const variables significantly from ye-old-days. Before the compiler had to prove that a const flagged variable was not being changed elsewhere before it could reuse a copy. In this version it has been redefined to be basically an alias of 'restrict' so the compiler will now assume the variable will not be aliased for the whole time it's in scope. This would appear to make 'const' less useful, perhaps even something to be avoided because it invokes 'unreasonable behaviour'. – user3710044 Mar 26 '15 at 09:28
1

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. 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++. 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. 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.

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. 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).

user3710044
  • 2,261
  • 15
  • 15