const关键字如何在c中工作

时间:2010-05-11 17:16:00

标签: c++ c

我想知道c和c ++中的const内部。编译器如何强加常量? 有人可以帮助我。

6 个答案:

答案 0 :(得分:23)

通常const是100%编译器。当你声明一些const时,编译器会对你写的内容施加限制。它不会让你分配给const标量,通过const引用或指针赋值,或者调用const对象的非const函数。

无法保证编译器会安排任何类型的运行时保护。

答案 1 :(得分:9)

C和C ++中的

const关键字有两种不同的语义含义。

(1)它可以声明对象的常量

const SomeType t;

在上面的例子中,对象t是一个不可修改的对象。编译器将尽力阻止您通过观察 const-correctness 规则(在C和C ++中不同)来修改它。 const-correctness规则仅在概念上强制执行,在语言级别,这意味着有办法绕过这些规则,这也意味着对象的constness不一定在物理层面实现。即无法保证对象最终会被放入只读存储器中。

重要的是要注意,这种常量不可移除在某种意义上,任何通过抛弃const修改上述对象的尝试都会导致未定义的行为(不包括可能的{{1} C ++中的成员。)

(2)它可以向对象声明访问路径的常量

mutable

上面的const SomeType *p; 被声明为指向const的指针。这并不一定意味着对象p指向的是一个常量对象(由上面第一种p定义)。它可能很容易成为非常量的,在这种情况下,从上面的访问路径中抛弃const并修改对象是完全合法的,尽管它通常不是一个好的编程实践。换句话说,访问路径的常量可能可移除

考虑到上述情况,以下声明

const

包括两种不同的const int* const* const* const p = 0; :最后一个const声明对象const(第一种)的常量,而p的其余部分声明常量由const(第二类)表示的各种访问路径级别。

P.S。作为一个[可能不相关]的旁注,值得注意的是,术语常量在C和C ++中具有截然不同的含义。在C ++中,常量是声明为p的对象。在C 常量中是文字。声明为const的对象在C术语中不是常量

答案 2 :(得分:4)

除了使用const关键字提供的编译时强制不变性,您的问题的其他答案已经提到过,使用它有时允许编译器将这些数据放在只读中二进制文件和内存的一部分。根据Ulrich Drepper的文章How To Write Shared Libraries中的第2.4.2节“永远const”,可能允许程序(1)使用更少的资源和(2)更快地启动。

请注意,像往常一样,在此类只读内存区域中丢弃数据的const会导致未定义的行为。

答案 3 :(得分:2)

当编译器编译代码时,它会计算每个表达式的类型,以便它可以对它们进行类型检查并正确发出代码(例如当您尝试在指针中存储int时的警告,或者正确地将整数转换为一个双)。 const - 可以将其视为该类型的一部分。由于它具有表达式的类型信息,因此它可以检查左值的类型(赋值的左侧),如果其类型中有'const',则抛出错误。

答案 4 :(得分:1)

在C中,const关键字将使变量成为不可变的,这意味着它不能被修改。

通常,这是编译时的区别,对变量的运行时修改没有影响。例如,可以使用指向相同内存地址的指针间接修改const变量。

在C ++中,const关键字具有多种含义。

例如,类成员函数可以是“const”,这意味着不允许修改类实例的状态。

与在C中一样,声明为const的变量也可以使用指针间接修改,但也可以使用“mutable”关键字或const_cast<>来修改。操作

答案 5 :(得分:1)

在优化编译器中,这实际上是一件非常复杂的事情。不过,它开始很简单。

当你使用const关键字声明一个变量时(让我们忽略指针,因为它们可以是const或指向const或两者),编译器会记住没有代码应该改变那个变量(差不多)。如果编译器看到更改const变量的代码,那么它会认为是错误(或偶尔只值得警告,但为了简单起见,我将忽略它)。编译器还假设没有它看不到的代码(现在无论如何{其他.c文件中的代码或可能的库或.s或.asm文件)将改变const变量(除非它是const volatile在这种情况下它会假设它可能随时改变,但仍会强制执行不让代码改变它 - 这对于用于读取设备状态但不能写入的内存映射SFR [特殊功能寄存器]很有用记住,c和c ++用于操作系统和嵌入式编程。

假设变量在某些或所有情况下都不会改变,这允许编译器的优化例程执行其他方式无法执行的操作。这意味着将变量的文字值放入指令流而不是加载变量的地址然后加载变量的值。它还可以假设如果加载了if:

extern const int foo; // note that the value isn't visible, so a load is necessary
...
extern int baz(int, int);
...
int bar(int x, int y) {
   int m, n;
   int r = x / foo; // this would require loading the value of foo from RAM
   m = baz(r, y); // the compiler normally has to assume that a function could change a global
   n = m + r + foo; // but since the global foo is const it shouldn't be able to be changed
                    // by the call to baz and does not need to be reloaded
   return n;
}

可执行文件(或其他目标文件)可能有一个只有常量的部分(.rodata)。在许多情况下,OS可能强制不允许程序写入该数据(或者在某些情况下甚至可能在ROM中)。本节还可能包含用于初始化的非常量变量的版本,因为它可能包含任何常量,而不仅仅是声明为const的常量。

所以在C const中,主要只是告诉编译器告诉你,你已经搞砸了,并试图改变一些本不应该改变的东西。但是,允许基于它做出一些假设。

在C ++中它变得更复杂。我不记得所有的细节,但我记得你可以根据传递给它的值是否为常量来重载函数名称,这可能很有用。

相关问题