我们可以修改const变量的值吗?

时间:2012-09-03 09:37:31

标签: c const

来自this article

  

将变量声明为registerconst的另一个用途是禁止该变量的任何非局部更改,即使通过获取其地址然后转换指针也是如此。即使您认为自己永远不会这样做,一旦将指针(即使使用const属性)传递给其他函数,您也永远无法确定这可能是恶意的并且更改变量在你的脚下。

我不明白我们如何通过指针修改const变量的值。是不是未定义的行为?

const int a = 81;
int *p = (int *)&a;
*p = 42; /* not allowed */

6 个答案:

答案 0 :(得分:11)

作者的观点是,声明具有register存储类的变量会阻止您获取其地址,因此无法将其传递给可能通过丢弃const来更改其值的函数。 / p>

void bad_func(const int *p) {
    int *q = (int *) p;            // casting away const
    *q = 42;                       // potential undefined behaviour
}

void my_func() {
    int i = 4;
    const int j = 5;
    register const int k = 6;
    bad_func(&i);                  // ugly but allowed
    bad_func(&j);                  // oops - undefined behaviour invoked
    bad_func(&k);                  // constraint violation; diagnostic required
}

通过将潜在的UB更改为约束违规,需要进行诊断并且在编译时诊断出错误

  

     

5.1.1.3诊断

     

1 - 如果是预处理翻译单元或翻译单元,符合要求的实施方案应至少产生一条诊断消息   包含违反任何语法规则或约束的行为,即使行为也是明确的   指定为未定义或实现定义。

     

6.5.3.2地址和间接运算符

     约束      

1 - 一元&运算符的操作数应为[...]左值,指定一个对象[...]   未使用register存储类说明符声明。

请注意,register数组对象上的数组到指针衰减是未定义的行为,不需要诊断(6.3.2.1:3)。

另请注意,在C ++中允许使用register左值的地址,其中register只是一个优化提示(并且在此处不推荐使用)。 / p>

答案 1 :(得分:2)

  

我们可以修改const变量的值吗?

是的,您可以通过各种方式修改const变量:指针hackery,强制转换等... 请阅读下一个Q !!

  

修改const变量的值是否有效?

没有!给你的是未定义的行为

技术上,您的代码示例具有未定义行为 修改const后,该程序不符合c标准,因此可能会给出任何结果。

请注意,未定义的行为并不意味着编译器需要将违规报告为诊断。在这种情况下,您的代码使用指针hackery来修改const,并且不需要编译器来为其提供诊断。

C99标准3.4.3 说:

  

未定义的行为:行为,在使用不可移植或错误的程序构造或错误数据时,本国际标准不对其施加任何要求。

     

注意可能的未定义行为包括完全忽略具有不可预测结果的情况,在转换或程序执行期间以环境特征(有或没有发出诊断消息)的文档方式执行,终止转换或执行(发布诊断信息)。

答案 2 :(得分:2)

您的代码已编译,但它具有未定义的行为。

作者的观点是使用const register,以便代码不再编译:

const int a = 81; 
int *p = (int *)&a; /* no compile error */
*p = 42; /* UB */ 

register const int b = 81; 
int *q = (int *)&b; /* does not compile */

答案 3 :(得分:1)

代码片段确实会调用未定义的行为。

我不确定作者的观点是什么:为了不让外国代码"更改变量const的值,以便调用... UB?这怎么可取?坦率地说,没有意义。

答案 4 :(得分:1)

我认为作者也在谈论这个案例,这是对const的误解:

 int a = 1;
 int* const a_ptr = (int* const)&a; //cast not relevant
 int function(int* const p){
     int* malicious = (int*)p;
     *malicious = 2;
 }

变量本身不是常量,而是指针。恶意代码可以转换为常规指针并合法修改下面的变量。

答案 5 :(得分:0)

我不明白我们如何通过指针修改const变量的值。这不是未定义的行为吗?


是的,这是未定义的行为:

引用自C18,6.7.3 / 7:

“如果试图通过使用具有非const限定类型的左值来修改以const限定类型定义的对象,则该行为是不确定的。”

但是仅仅因为行为是不确定的,并不意味着您潜在地无法做到这一点。据我所能想到的,确实如此,在大多数情况下,编译器会在程序中包含任何未定义的行为,会警告您-这是一个大问题。< / p>

幸运的是,在这种情况下,编译f.e。:

#include <stdio.h>

int main(){
    const int a = 25;
    int *p = &a;

    *p = 26;

    printf("a = %d",a);
}

编译器将发出警告:

初始化会从指针目标类型[-Wdiscarded-qualifiers(gcc)

中丢弃'const'限定符

警告:使用类型为'const int *'的表达式初始化'int *'会丢弃限定符[-Wincompatible-pointer-types-discards-qualifiers](clang)

但是,尽管代码中包含导致未定义行为的部分,并且您无法确定在任何执行中将打印出什么内容,但还是会编译该恶意程序(当然没有-Werror选项)。


我们可以修改const变量的值吗?

是的,很不幸。人们实际上可以修改const对象,但是您永远都不应这样做,无论是有意还是无意的。

使用register关键字的方法可能很有效,因为标记为register的变量的地址无法获取其地址-意味着您不能为指针分配相对变量的地址,也不能将其作为相应指针类型的参数传递给函数。