【问题标题】:How is "const" implemented?“const”是如何实现的?
【发布时间】:2011-10-25 17:21:28
【问题描述】:

C 或 C++ 编译器(例如 gcc)如何遵守 const 声明?

例如,在下面的代码中,编译器如何跟踪变量ciconst并且不能修改?

int
get_foo() {
    return 42;
}

void
test()
{
    int i = get_foo();
    i += 5;

    const int ci = get_foo();
    // ci += 7;  // compile error: assignment of read-only variable ?ci?
}

【问题讨论】:

  • 跟踪所有关于变量的编译时信息的方式是一样的?
  • 这是在编译时通过类型系统完成的。
  • 您的评论应为“赋值给只读变量”。顺便说一句,您认为编译器如何知道它的整数?
  • 为什么不去看看像clang这样的免费编译器的源代码呢?

标签: c++ c constants


【解决方案1】:

很像变量的任何其他符号信息(地址、类型等)。通常有一个符号表来存储有关已声明标识符的信息,并且每当遇到对该标识符的另一个引用时都会对其进行查询。

(一个更有趣的问题是这种知识是否只存在于编译期间甚至在运行时。大多数语言在编译后会丢弃符号表,因此即使声明了标识符,您也可以操纵编译后的代码并强制一个新值' const'。它需要一个复杂的运行时系统(和代码签名)来防止这种情况。)

【讨论】:

  • 除此之外,标准问题 C++/C 编译器并没有做太多事情来在运行时保留这样的“const”变量,它只知道不生成任何可能的代码通过 Kilian 提到的符号表修改此值。因此,其他一些编译器可以创建一些代码,如果该代码被加载到进程中,它可能会覆盖该位置的内存。这很糟糕。
  • 常量数据可以放在不同的内存块中,并且在某些系统上,该内存块实际上会被标记为只读。就像代码本身驻留在不同的段中一样(也许 const 数据和代码可能混合在一起)。当然,这只适用于静态常量,并且不会在堆栈上创建任何内容。
【解决方案2】:

当然,这取决于每个编译器的实现,但简而言之,它将变量的constvolatile 限定符(如果有)连同其他信息(例如变量的类型和是否为指针/引用。

【讨论】:

  • “简历限定词”?变量肯定没有简历!
  • @Gabe:标准在第 3.9.3 节“CV 限定符”中对它们进行了很多讨论(const/volatile)。
【解决方案3】:

正如其他人所说,编译器跟踪const 的方式与编译器跟踪变量是int 事实的方式相同。事实上,我已经读到至少 gcc 认为 const int 是与 int 不同的类型,因此它甚至没有作为修饰符进行跟踪,它的跟踪方式与 int 完全相同。

请注意,您实际上可以通过指针转换来更改 const 的值,但结果是未定义的:

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

int main(void) {
        const int c = 0;
        printf("%d\n", c);
        ++*(int*)&c;
        printf("%d\n", c);
}

在我使用 gcc 的机器上,打印出来

0
1

但是用 g++ 编译会得到

0
0

【讨论】:

    【解决方案4】:

    我相信其他人可以详细说明,但简而言之,是的。编译器会跟踪所有类型说明符,以便它知道 ci 的类型是“const int”,而不是“int”。

    【讨论】:

      【解决方案5】:

      编译器知道ciconst,因为你在这行告诉它

      const int ci = get_foo();
      

      当您将ci 传递给其他函数或将其分配给其他变量时,编译器会通过阻止您执行任何可能更改其值的操作来保留该常量。

      例如,以下会产生编译器错误。

      int *ci2 = &ci;
      (*ci2)++;
      

      因为编译器不会让你修改 ci 的值。

      【讨论】:

      • 即使没有增量操作,后一个示例也会产生编译器错误。不能将指向 const 的指针分配给指向非 const 变量的指针。
      猜你喜欢
      • 2020-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-10
      • 2012-10-11
      相关资源
      最近更新 更多