7

这篇文章

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

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

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

6 回答 6

11

作者的观点是,使用register存储类声明变量会阻止您获取其地址,因此无法将其传递给可能通过强制转换来更改其值的函数const

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

于 2012-09-03T10:00:23.403 回答
4

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

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

const修改变量的值是有效的代码吗?

不!给你的是Undefined Behavior

从技术上讲,您的代码示例具有Undefined Behavior
一旦您修改了程序,该程序就不会遵守 c 标准const,因此可能会给出任何结果。

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

C99 标准 3.4.3说:

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

注意 可能的未定义行为范围从完全忽略具有不可预测结果的情况,到在翻译或程序执行期间以环境特征的记录方式表现(有或没有发出诊断消息),到终止翻译或执行(使用发出诊断消息)。

于 2012-09-03T09:40:01.230 回答
2

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

作者的观点是使用const and 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 */
于 2012-09-03T10:00:08.227 回答
1

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

我不太确定作者的意思是什么:为了不让“外来代码”更改您创建的变量的值,const以便... UB 被调用?那如何更可取?坦率地说,这没有任何意义。

于 2012-09-03T09:44:17.953 回答
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;
 }

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

于 2012-09-03T09:56:56.163 回答
0

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


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

引自 C18, 6.7.3/7:

“如果尝试通过使用具有非 const 限定类型的左值来修改使用 const 限定类型定义的对象,则行为未定义。”

但仅仅因为行为未定义,并不意味着您可能无法做到这一点。据我所知,情况确实如此,大多数时候你的程序包含任何未定义的行为,而不是警告你——这是一个大问题。

幸运的是,在这种情况下,编译 fe 时:

#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标记变量的地址不能获取其地址 - 这意味着您不能为指针分配相对变量的地址,也不能将其作为相应指针类型的参数传递给函数。

于 2020-03-12T17:41:40.530 回答