【问题标题】:gcc -O2 flag affect while modifying const int修改 const int 时 gcc -O2 标志影响
【发布时间】:2014-02-03 05:29:14
【问题描述】:

我知道在 C 中我们可以通过指针修改“const int”。但是在编译程序时我在gcc中启用了'-O2'标志,而const int不能修改该值,所以只想知道gcc优化标志如何影响修改'const int'。

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

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

【问题讨论】:

  • 我收到警告。 initialization discards ‘const’ qualifier from pointer target type.
  • “我知道在 C 中我们可以通过指针修改 'const int'”请问?

标签: c gcc


【解决方案1】:

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

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

任何有价值的编译器都会对此发出警告。使用 default 编译器选项,当我尝试编译代码时,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;
             ^      ~~

【讨论】:

  • 是的,它也给了我警告,但我能够得到值,但是当我添加优化标志时,值不能改变。我之前读过stackoverflow.com/questions/945640/constants-and-pointers-in-c/…这个问题,我理解了c中const的行为,但无法理解带有优化标志的行为。
  • @skanzariya - 在优化时您可能看不到由于constant propagation 的任何修改结果。但是很难解释明确未定义的行为。
  • 嗨@Brett,感谢您的写作,是的,很难理解未定义的行为,我知道'const'但想深入了解一下。谢谢。
【解决方案2】:

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

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

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

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

【讨论】:

    【解决方案3】:

    这一行是违反约束

    int *iPtr = &i;
    

    &amp;i 的类型是const int *。当前 C 标准(“简单赋值”)的第 6.5.16.1/1 节涵盖了代码的行为,其中列出了赋值约束。

    这些限制的一部分是不允许左操作数指向非限定类型,而右操作数是指向限定类型​​的指针。

    如果编译器在标准兼容模式下运行,它必须提供诊断消息。它可能无法生成可执行文件。如果编译器确实继续执行其他任何操作,则该行为不再包含在标准中。 (换句话说,该程序具有完全未定义的行为)。

    注意。其他答案提到“修改 const 对象”,但这并不相关,因为在尝试修改对象之前发生约束违规;并且在违反约束后所有赌注都被取消。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-08
      • 2015-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多