C -GCC -O2标志在修改const int时影响



我知道我们可以通过指针修改'const int'。但是,在编译程序时,我在GCC中启用了" -O2"标志,而const int无法修改该值,因此只想知道GCC优化标志如何影响修改的" const int"。

这是示例应用程序测试。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

这种好奇心使我写了这个问题。

我知道在C中我们可以通过指针修改" const int"。

不,这是错误的。C语言标准清楚地表明,修改const对象是"未定义的行为"。这意味着任何事情都可能发生 - 代码可能会成功,可能会崩溃,它可能会破坏您的硬盘驱动器,或者使恶魔从鼻子中飞出。所有这些行为都被认为是合法的。因此,根据编译器的优化级别,行为变化的事实也完全合法。

任何值得盐的编译器都会警告您。使用默认编译器选项,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是相似的:

$ 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;
             ^      ~~

修改称为 const的变量是未定义的行为。未定义的行为是...未定义;换句话说,编译器可以做任何,包括,假设未定义的行为实际上并没有发生。

在这种情况下,编译器可以通过假设它从不更改来优化对const int i的访问;这使编译器可以在printf调用中插入i的已知初始值。实际上,它可以预先计算要在编译时输出的字符串,因为它知道应该做什么printf

您可以通过指针绕过const声明是不正确的。如果最初将变量声明为const,则尝试修改该变量是无效的。您可以做的是创建一个const指针,指向一个可变变量,然后通过将其扔掉来围绕指针的const NESS。由于原始变量不是const,所以这是合法的(尽管通常不是一个好主意。)

(强制性标准参考:&sect; 6.7.3/6:"如果尝试通过使用具有非统一合格类型的LVALUE来修改用constemified类型定义的对象,则该行为是未定义的。")

此行是约束违规

int *iPtr = &i;

&i的类型是const int *。当前C标准("简单分配")的第6.5.16.1/1节涵盖了代码的行为,该节列出了分配中的约束。

这些约束的一部分是,在正确的操作数是合格类型的指针的同时,左派操作数不允许将其指向不合格的类型。

如果编译器以标准模式运行,则必须提供诊断消息。它可能无法生成可执行文件。如果编译器确实继续做其他任何事情,那么标准不再涵盖行为。(换句话说,该程序具有完整的未定义行为)。

nb。其他答案提到了"修改const对象",但是这与违规的违规行为无关,因为在任何尝试修改对象之前发生了违规行为。

,所有赌注都关闭。

最新更新