GCC:在获取地址时取消引用“ void *”指针

时间:2019-01-25 23:18:20

标签: c pointers gcc language-lawyer void

我注意到GCC触发器:

warning: dereferencing ‘void *’ pointer

同时采用已取消引用的void表达式的地址,例如:

int main()
{
    void *p = "abcdefgh";

    printf("%p\n", p);
    printf("%p\n", &*p);

    return 0;
}

但是,根据C标准,表达式p等效于&*p

  

§6.5.3.2地址和间接运算符

     

一元&运算符返回其操作数的地址。如果操作数的类型为“类型”,则结果的类型为“要输入的指针”。如果操作数是一元*运算符的结果,则不会对该运算符和&运算符求值,并且结果似乎都被省略了,除了运算符上的约束仍然适用并且结果不是左值。

了解Clang不会触发此警告也很重要。

免责声明

为获得更好的解释,请考虑以下问题:

int main()
{
    int *p = NULL;

    printf("%p\n", (void *) p);
    printf("%p\n", (void *) &*p);

    return 0;
}

此代码可与Clang和GCC一起编译并完美运行。 C标准对void指针很明确,您可以取消引用它们(从而获得一个void值),但不能使用该表达式的结果。

1 个答案:

答案 0 :(得分:2)

我假设这里的问题是“为什么?/给什么?”。 在那种情况下,这实际上是一些标准的措辞/为开发人员提供灵活性。

严格来说,*(void*)总是很糟糕,编译器可以警告您。 在实践中,正如您正确指出的那样,在评估指针所指向的内容时,指针实际上从未真正被取消引用,因此,天真的编译器实现将以这种方式查看并毫无问题地进行掩饰这并说“指针:它们是数字吗?这个是0xFFF ....”。

在实践中,尽管有时并非如此。有时候编译器变得很聪明。没有想到好的例子,但这不是重点。

关于“它从未被评估”,我认为可能需要注意以下几点:

给予编译器自由执行其所需功能的原因,部分是为了简化编译过程本身,而不仅仅是输出更好的实现。 您指向的下一个编译器可能会拒绝。只是因为它更容易,而且没有必要。

第二,这并不是警告的重点。如果我在代码审查中看到了这一点:

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

我的反应不会是:“哦,很好,没有评估。”但是“哇!”。这也是编译器所做的。它告诉您,它认为您可能已经做了您可能需要重新考虑的事情,在这种情况下,称const char *void *。我同意gcc。