简体   繁体   中英

gcc -O2 flag affect while modifying const int

I know in C we can modify the 'const int' via pointer. But while compiling the program I enabled the '-O2' flag in gcc, and const int can't modify the value, so just wanted to know how gcc optimization flag affect the modifying 'const int'.

Here is the sample application test.c

#include <stdio.h>
#include <stdlib.h>

int main(int ac, char *av[])
{
        const int i = 888;
        printf("i is %d \n", i);
        int *iPtr = &i;
        *iPtr = 100;
        printf("i is %d \n", i);
        return 0;
}

gcc -Wall -g -o test test.c
./test
i is 888 
i is 100

gcc -Wall -g -O2 -o test test.c
i is 888 
i is 888

This curiosity leads me to write this question.

It's undefined behaviour to modify a variable declared as const . Undefined behaviour is... undefined; in other words, the compiler can do anything including assuming that the undefined behaviour does not actually happen.

In this case, the compiler can optimize the access to const int i by assuming that it is never changed; that allows the compiler to insert the known initial value of i in the call to printf . In fact, it could precompute the string to be output at compile time, since it knows what printf is supposed to do.

It's not true that you can by-pass const declarations through pointers. If a variable is originally declared as const , attempts to modify it are not valid. What you can do is create a const pointer to a mutable variable, and then later get around the const ness of the pointer by casting it away. Since the original variable is not const , that is legal (although not usually a good idea.)

(Obligatory standard reference: §6.7.3/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.")

I know in C we can modify the 'const int' via pointer.

Nope, that's wrong. The C language standard clearly says that modifying a const object is "undefined behavior". That means that anything at all could happen—the code could succeed, it could crash, it could corrupt your hard drive, or make demons fly out of your nose. All of those behaviors are considered legal. So, the fact that the behavior changes depending on the compiler's optimization level is also perfectly legal.

Any compiler worth its salt will warn you about this. With the default compiler options, GCC helpfully tells me this when I try to compile the code:

$ gcc test.c
test.c: In function 'main':
test.c:8:21: warning: initialization discards 'const' qualifier from pointer target type [enabled by default]

Clang is similar:

$ clang test.c
test.c:8:14: warning: initializing 'int *' with an expression of type
      'const int *' discards qualifiers
      [-Wincompatible-pointer-types-discards-qualifiers]
        int *iPtr = &i;
             ^      ~~

This line is a constraint violation :

int *iPtr = &i;

The type of &i is const int * . The behaviour of the code is covered by section 6.5.16.1/1 of the current C Standard ("Simple assignment") which lists the constraints on assignment.

Part of those constraints is that it is NOT permitted for the left operand to be pointer to unqualified type while the right operand is a pointer to qualified type.

If the compiler is operated in standard-compliant mode, it must offer a diagnostic message. It may fail to generate an executable. If the compiler does go on to do anything else then the behaviour is no longer covered by the Standard. (In other words, the program has completley undefined behaviour).

NB. Other answers mention "modifying a const object", however that is not relevant as the constraint violation occurs before any attempt to modify an object; and all bets are off after the constraint violation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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