GCC:在获取地址时取消引用“void *”指针
GCC: dereferencing ‘void *’ pointer while taking address
我注意到 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
值)但您不能使用表达式的结果。
我假设这里的问题是 "Why is that?/What gives?"。
在这种情况下,这确实有点标准措辞/编译器开发人员的灵活性问题。
严格来说*(void*)
总是不好的,编译器警告你是对的。
在实践中,正如您正确指出的那样,指针从未真正真正取消引用,在评估您在它指向的方向上看到的内容时,因此编译器的天真实现不会以您的方式看到这一点,并掩盖这并说 "pointers: they're numbers right? this one is 0xFFF....".
在实践中,尽管有时情况并非如此。有时编译器会变得非常聪明。没有很好的例子 spring 但这不是重点。
关于 "it's never evaluated" 我认为可能值得注意的几件事:
编译器可以自由地做他们想做的事情的部分原因是为了简化编译过程本身,而不仅仅是输出更好的实现。
可能你指向它的下一个编译器会说不。只是因为它更容易而且不需要。
其次,这并不是警告的重点。如果我在代码审查中看到这个:
int i = 3;
if (3-i) {
((int*)(NULL)) += 4;
}
我的反应不是:"Oh okay that's fine, its not evaluated."而是"Whoa hang on a second: why?"。这也是编译器所做的。它告诉你它认为你可能已经做了一些你可能想要重新考虑的事情,在这种情况下调用 const char *
和 void *
。一方面,我同意 gcc。
我注意到 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
值)但您不能使用表达式的结果。
我假设这里的问题是 "Why is that?/What gives?"。 在这种情况下,这确实有点标准措辞/编译器开发人员的灵活性问题。
严格来说*(void*)
总是不好的,编译器警告你是对的。
在实践中,正如您正确指出的那样,指针从未真正真正取消引用,在评估您在它指向的方向上看到的内容时,因此编译器的天真实现不会以您的方式看到这一点,并掩盖这并说 "pointers: they're numbers right? this one is 0xFFF....".
在实践中,尽管有时情况并非如此。有时编译器会变得非常聪明。没有很好的例子 spring 但这不是重点。
关于 "it's never evaluated" 我认为可能值得注意的几件事:
编译器可以自由地做他们想做的事情的部分原因是为了简化编译过程本身,而不仅仅是输出更好的实现。 可能你指向它的下一个编译器会说不。只是因为它更容易而且不需要。
其次,这并不是警告的重点。如果我在代码审查中看到这个:
int i = 3;
if (3-i) {
((int*)(NULL)) += 4;
}
我的反应不是:"Oh okay that's fine, its not evaluated."而是"Whoa hang on a second: why?"。这也是编译器所做的。它告诉你它认为你可能已经做了一些你可能想要重新考虑的事情,在这种情况下调用 const char *
和 void *
。一方面,我同意 gcc。