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

标签 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 Address and indirection operators

The unary & operator returns the address of its operand. If the operand has type ‘‘type’’, the result has type ‘‘pointer to type’’. If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue.

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

免责声明

为了更好的解释,考虑这个:

int main()
{
    int *p = NULL;

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

    return 0;
}

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

最佳答案

我假设这里的问题是“这是为什么?/什么给了?”。 在这种情况下,这实际上是一个标准措辞/编译器开发人员灵 active 问题。

严格来说 *(void*) 总是不好的,编译器警告你是对的。 在实践中,正如您正确指出的那样,指针从未真正真正取消引用,在评估您在它指向的方向上看到的内容时,因此编译器的天真实现不会以您的方式看到这一点,并掩盖这个并说“指针:它们是数字,对吗?这个是 0xFFF ....”。

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

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

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

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

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

我的 react 不会是:“哦,没关系,它没有被评估。”但是“哇等一下:为什么?”。这也是编译器所做的。它告诉您它认为您可能已经做了一些您可能想要重新考虑的事情,在这种情况下调用 const char *void *。一方面,我同意 gcc。

关于c - GCC:在获取地址时取消引用 ‘void *’ 指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54374066/

相关文章:

ubuntu - 在 ubuntu 上安装交叉编译器

c - 如果我用 `-pedantic` 指定 ANSI C 的标准,我还需要 `-std=c89` 吗?

自定义全局热键

c - C中B+树的简单实现

c - 我的c代码有什么问题? (可能是 malloc 调用)

使用指针的 C 数组求和?

c - 打印包含元音的子字符串

c - 摆脱 typedef 引起的 "Incompatible pointer"警告

C - 指向随机值的指针

linux - 查找已编译的可执行文件的版本