【发布时间】:2021-12-22 01:04:18
【问题描述】:
基本上,启用严格别名后这段代码合法吗?
void f(int *pi) {
void **pv = (void **) π
*pv = NULL;
}
这里,我们通过另一种类型的指针(指向void *的指针)访问一种类型的对象(int*),所以我想说这确实是一个严格的别名违规。
但是试图突出未定义行为的示例让我怀疑(即使它不能证明它是合法的)。
首先,如果我们给int *和char *加上别名,我们可以根据优化级别得到不同的值(所以肯定是违反严格别名的):
#include <stdio.h>
static int v = 100;
void f(int **a, char **b) {
*a = &v;
*b = NULL;
if (*a)
// *b == *a (NULL)
printf("Should never be printed: %i\n", **a);
}
int main() {
int data = 5;
int *a = &data;
f(&a, (char **) &a);
return 0;
}
$ gcc a.c && ./a.out
$ gcc -O2 -fno-strict-aliasing a.c && ./a.out
$ gcc -O2 a.c && ./a.out
Should never be printed: 100
但是使用void ** 而不是char ** 的相同样本不会表现出未定义的行为:
#include <stdio.h>
static int v = 100;
void f(int **a, void **b) {
*a = &v;
*b = NULL;
if (*a)
// *b == *a (NULL)
printf("Should never be printed: %i\n", **a);
}
int main() {
int data = 5;
int *a = &data;
f(&a, (void **) &a);
return 0;
}
$ gcc a.c && ./a.out
$ gcc -O2 -fno-strict-aliasing a.c && ./a.out
$ gcc -O2 a.c && ./a.out
只是偶然吗?还是void ** 的标准中有明确的例外?
或者也许只是编译器处理void **,因为实际上(void **) &a 在野外太常见了?
【问题讨论】:
-
没有什么可以打破严格的别名规则。您分配的指针不通过不兼容的引用引用数据。 NULL 适用于任何指针类型。顺便说一句,您在通过应用强制转换调用函数时使警告静音
-
但是如果我们使用
char **而不是void **,我们会表现出未定义的行为。这里,数据是int *(不是int),我们通过指向void *的指针访问它,所以我们通过不兼容的(?)指针访问它。 -
@0___________ 这些是指针变量本身的严格别名违规行为,而不是指向的数据。
标签: c language-lawyer undefined-behavior strict-aliasing