简体   繁体   English

修改const int时gcc -O2标志会产生影响

[英]gcc -O2 flag affect while modifying const int

I know in C we can modify the 'const int' via pointer. 我知道在C中我们可以通过指针修改'const int'。 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'. 但是在编译程序时我在gcc中启用了'-O2'标志,并且const int无法修改该值,所以只想知道gcc优化标志如何影响修改'const int'。

Here is the sample application test.c 这是示例应用程序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 . 修改声明为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; 在这种情况下,编译器可以通过假设它永远不会改变来优化对const int i的访问; that allows the compiler to insert the known initial value of i in the call to printf . 允许编译器在对printf的调用中插入i的已知初始值。 In fact, it could precompute the string to be output at compile time, since it knows what printf is supposed to do. 事实上,它可以预先计算在编译时输出的字符串,因为它知道printf应该做什么。

It's not true that you can by-pass const declarations through pointers. 你可以通过指针绕过const声明,这是不正确的。 If a variable is originally declared as const , attempts to modify it are not valid. 如果变量最初声明为const ,则尝试修改它无效。 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. 你可以做的是创建一个指向可变变量的const指针,然后通过将其抛弃来绕过指针的const Since the original variable is not const , that is legal (although not usually a good idea.) 由于原始变量不是const ,这是合法的(虽然通常不是一个好主意。)

(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.") (强制性标准参考:§6.7.3/ 6:“如果尝试通过使用具有非const限定类型的左值来修改使用const限定类型定义的对象,则行为是未定义的。”)

I know in C we can modify the 'const int' via pointer. 我知道在C中我们可以通过指针修改'const int'。

Nope, that's wrong. 不,那是错的。 The C language standard clearly says that modifying a const object is "undefined behavior". C语言标准明确指出修改const对象是“未定义的行为”。 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在我尝试编译代码时有用地告诉我:

$ 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类似:

$ 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 * . &i的类型是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. 当前C标准(“简单分配”)的6.5.16.1/1部分涵盖了代码的行为,其中列出了赋值的约束。

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. 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; 其他答案提到“修改const对象”,但是这与在任何修改对象的尝试之前发生约束违规无关; and all bets are off after the constraint violation. 并且在违反约束后所有投注均已关闭。

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

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