c-GCC:获取地址时取消引用"void*"指针



我注意到GCC触发器:

warning: dereferencing ‘void *’ pointer

在获取未引用的void表达式的地址时,如:

int main()
{
void *p = "abcdefgh";
printf("%pn", p);
printf("%pn", &*p);
return 0;
}

然而,根据C标准,表达式p等效于&*p

§6.5.3.2地址和间接运算符

一元&运算符返回其操作数的地址。如果操作数的类型为"type",则结果的类型是"pointer to type"。如果操作数是一元*运算符的结果,则该运算符和&运算符被求值,结果就像两者都被省略了一样,只是对运算符的约束仍然适用,并且结果不是左值。

同样重要的是要知道Clang不会触发此警告。

免责声明

为了得到更好的解释,请考虑以下内容:

int main()
{
int *p = NULL;
printf("%pn", (void *) p);
printf("%pn", (void *) &*p);
return 0;
}

这段代码可以与Clang和GCC完美地编译和运行。C标准对void指针很清楚,您可以取消引用它们(从而获得void值),但不能使用表达式的结果。

我假设这里的问题是"为什么?/给出了什么?"。在这种情况下,对于编译器开发人员来说,这实际上是一个标准措辞/灵活性的问题。

严格地说,*(void*)总是不好的,编译器警告您是正确的。在实践中,正如你正确地指出的那样,指针从来没有真正被取消引用,在评估中,你在它指向的方向上看到了什么,所以编译器的天真实现不会有问题,你可以这样看,并掩盖这一点,说"指针:它们是数字,对吧?这个是0xFFF……"。

但在实践中,有时情况并非如此。有时编译器会变得非常聪明。脑海中没有好的例子,但这不是重点。

关于"从未评估过",我认为有几件事可能值得注意:

编译器可以自由地做他们想做的事情,部分原因是为了简化编译过程本身,而不仅仅是为了输出更好的实现。你指向的下一个编译器可能会说不。只是因为它更容易,而且不必这么做。

其次,这并不是真正的警告意义。如果我在代码审查中看到这一点:

int i = 3;
if (3-i) {
((int*)(NULL)) += 4;
}

我的反应是:"哦,好吧,没关系,没有评估。"但"哇,等一下:为什么?"。这也是编译器所做的。它告诉你,它认为你可能已经做了一些你可能想重新考虑的事情,在这种情况下,将const char *称为void *。I、 首先,同意gcc的观点。

最新更新