In my answer https://stackoverflow.com/a/46234805/2411320我提到取消引用void
指针是一个坏主意。但是,当我这样做时会发生什么?
#include <stdlib.h>
int main (void) {
void* c = malloc(4);
*c;
&c[0];
}
汇编:
gcc prog.c -Wall -Wextra
prog.c: In function 'main':
prog.c:4:2: warning: dereferencing 'void *' pointer
*c;
^~
prog.c:5:4: warning: dereferencing 'void *' pointer
&c[0];
^
prog.c:5:2: warning: statement with no effect [-Wunused-value]
&c[0];
^
对于那些说这没有发生的人来说,这是来自 Wandbox 的图片:
and a Live demo in Ideone.
它实际上会尝试读取内存中的内容c
指向has,然后获取该结果,但最终实际上什么也没做?或者这一行根本没有任何效果(但是 GCC 不会产生警告)。
我认为,由于编译器对数据类型一无所知,因此在不知道类型大小的情况下,它无法做太多事情。
为什么取消引用void*
不会产生错误,而只是警告?
如果我尝试分配,我会收到错误:
void 表达式的使用无效
但单独取消引用不应该产生错误吗?
C 标准明确指出5.1.1.3p1 http://port70.net/%7Ensz/c/c11/n1570.html#5.1.1.3:
符合要求的实施应产生至少一条诊断消息(以实现定义的方式标识)如果预处理翻译单元或翻译单元包含违反任何语法规则或约束的行为,即使该行为也显式指定为未定义或实现定义。在其他情况下不需要产生诊断消息。 9)
脚注 9 说
其目的是实施应识别每项违规行为的性质,并在可能的情况下定位每项违规行为。当然,只要仍然正确翻译有效的程序,实现就可以自由地产生任意数量的诊断。它还可能成功翻译无效程序。
因此,GCC 完全符合 C 标准。您的程序是无效程序。只需要一条诊断消息 - 并且允许编译器成功翻译您的无效程序。由于海湾合作委员会有一个非标准扩展为空指针算术 https://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html:
在 GNU C 中,指针支持加法和减法运算void
以及指向函数的指针。这是通过处理 a 的大小来完成的void
或函数为1
.
这样做的一个后果是sizeof
也允许void
以及函数类型,并返回1
.
选项-Wpointer-arith
如果使用这些扩展,则请求警告。
它决定对您的无效程序执行一些“明智”的操作并成功翻译它。
请注意,未评估的取消引用指向空指针已经需要在sizeof
, 因为:
void *foo;
sizeof *foo;
必须匹配
sizeof (void);
它们的计算结果都为 1,因此更容易允许丢弃指向 void 的指针的取消引用到处.
正如 Lundin 所说,如果您想要约束违规的实际错误,请使用-std=c11 -pedantic-errors
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)