【问题标题】:Why local constant variables doesnt go to .rodata section?为什么局部常量变量不去 .rodata 部分?
【发布时间】:2013-02-28 02:01:11
【问题描述】:
#include <stdio.h>

void inc(int* p) {
        *p = *p + 1;
}

int main() {
        const int a = 10;
        inc(&a);
        printf("%d\n",a);
}

上面的程序编译没有任何错误,输出为 11,因为局部变量 'a' 进入堆栈。

所以我的问题是:

  1. 为什么“a”进入堆栈。我期待它进入 .rodata 部分。但为什么没有呢?
  2. 如果我将 'a' 声明为全局常量变量,它会进入 .rodata 部分。

这让我很开心!!

【问题讨论】:

  • C 标准允许对 const 变量进行变异。使用 C++ 编译器会出现编译器错误。

标签: c compiler-construction constants elf


【解决方案1】:

除了名称以外,const 不声明 C 中的常量,而是声明不可修改的变量。它必须在“堆栈”上实现它,因为函数的递归调用必须导致该变量的不同实例化。 (这些可以通过它们的地址来区分。)在您的情况下,您的函数不会递归导致可能的优化,但不一定要采用这种优化路径。

至于违反const 属性,每个编译器都必须给你一个“诊断”,这是你自己的风险。

【讨论】:

    【解决方案2】:

    编译器可以为所欲为。如果你声明它static,你可能会得到你正在寻找的行为。

    在这种特定情况下,您尝试修改 const 值会导致未定义的行为,因此真的所有赌注都失败了。

    例如,我刚刚在这里使用clang 构建了您的确切程序,我得到了10 的输出。它确实给出了关于丢弃 const 限定符的警告:

    example.c:9:13: warning: passing 'const int *' to parameter of type 'int *' discards qualifiers [-Wincompatible-pointer-types]
            inc(&a);
                ^~
    example.c:3:15: note: passing argument to parameter 'p' here
    void inc(int* p) {
                  ^
    1 warning generated.
    

    【讨论】:

    • 是的,我看到它是一种未定义的行为,而静态可以解决问题。但我只是想知道为什么 gcc 会这样做,是否有任何原因?!?
    • 当涉及到未定义的行为时,您可以指望的唯一原因是编译器工程师最容易实现的。即使这样也很难保证。
    • 好吧,我看到编译器编写者的工作因为糟糕的程序员而变得困难。我无法投票,但感谢您的回答! :)
    【解决方案3】:

    在 C 中,“常量变量”实际上是承诺不会改变的变量,仅此而已。如果它是函数的局部变量,则它会像任何其他变量一样被创建、初始化和销毁​​。唯一不同的是,如果你(公开地)试图改变它,你会被尖叫。即:

    const int a = 15;
    ...
    a = 17;  /* error: assignment of read-only variable ‘a’ */
    ...
    int *p = (int *) &a;
    ...
    *p = 117; /* Just fine, will even work making a == 117 */
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-24
      • 2021-05-21
      • 1970-01-01
      • 2015-02-16
      • 1970-01-01
      • 2021-05-29
      相关资源
      最近更新 更多