const关键字如何在c中工作

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

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

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

C和C ++中的const关键字有两种不同的语义含义。

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

 const SomeType t; 

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

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

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

 const SomeType *p; 

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

考虑到上述因素,以下声明

 const int* const* const* const p = 0; 

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

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

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

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

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

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

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

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

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

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

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

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

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

 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变量的版本,因为它可能包含任何常量,而不仅仅是声明为const的常量。

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

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