告诉我,标准真的说绕过
const对象是未定义的行为吗?我试图自己找到这些信息,但没有成功。如果情况确实如此(我几乎可以肯定),那么我不太明白这条规则在什么情况下适用。
例如,即使在这样一个简单的例子中,也不是一切都是显而易见的:
const int a = 1; int *b = (int*)&a;// Это уже UB или еще нет? *b = 2;// Это точно UB?我无法对此做出任何假设:
const int *a = malloc(sizeof(int)); int *b = (int*)a;// UB? *b = 1;// UB?这也不清楚:
int i = 1; const int *a = &i; // Может, на следующей строке компилятор посчитает, что объект, // на который указывает "a", является константным? int *b = (int*)a; *a = 2;// И эта операция приведет к UB?和这个:
// Абсолютно необходимая функция... void f(void *const _p) { void **p = (void**)&_p; *p = NULL; }我经常在公司的代码指南中遇到
const尽可能使用它的要求。例如,有一个函数将指向数据的指针放入链表中。由于该函数不会更改数据或指向数据的指针以及指向容器本身的指针,因此该函数通常如下所示:int list_push_front(list *const _list, const void *const _data) { // ... // И приходится делать так... new_node->data = (void*)_data; // ... }但我们只是想说,该函数不会更改插入到列表中的数据,也不会更改输入指针参数,从而保护项目免受某些类型的ninja bug的影响。
有可能这样做吗?那真的是礼貌吗,还是接下来的演员
(void*)是UB?
标准 C11 6.7.3/6:
目前还没有修改,只是分配了不兼容的指针类型。这是违反约束的,但还不是 UB。
标准中有一个类似的例子(6.5.16.1/6):
分配被认为是不安全的,因为 允许你改变常数值(上面说这是UB),但是转换本身并没有给出UB。
更详细一点:
如果您打印这些值
*p并在此代码之后c,您可以看到例如以下内容:0 00 65未定义行为的典型结果。在第一种情况下,常数设置为零,在第二种情况下,本质上相同的数据具有不同的值。
右边的表达式不是一个常数,即 如果这里没有左边,分配的内存
malloc是可以修改的,也就是说它的间接改变不是一个常量对象的改变,即 可接受的。这是我的反思,您需要更详细地查看标准。您问题第 3 点的转换与第 1 点的情况基本相同。我们只是将指针转换为存储。将来,如果原始数据是可变的(未声明为
const),则可以使用新指针更改此数据,否则我们得到UB。顺便说一句,所有 UB 的列表在第J.2 节未定义的标准行为中给出。