这个语句会产生什么结果?
void *p = malloc(sizeof(void));
编辑:问题的扩展。如果在GCC编译器中sizeof(void)返回1,那么将分配1字节的内存并使指针p指向该字节。如果p开始时是0x2345,那么p++会递增到0x2346吗?我在谈论p而不是*p。
这个语句会产生什么结果?
void *p = malloc(sizeof(void));
编辑:问题的扩展。void
类型没有大小;这样做会导致编译错误。出于同样的原因,您不能执行以下操作:
void n;
编辑:
令我惊讶的是,在GNU C中执行sizeof(void)
实际上可以编译:
$ echo 'int main() { printf("%d", sizeof(void)); }' | gcc -xc -w - && ./a.out
1
然而,在C++中它并不会这样:
$ echo 'int main() { printf("%d", sizeof(void)); }' | gcc -xc++ -w - && ./a.out
<stdin>: In function 'int main()':
<stdin>:1: error: invalid application of 'sizeof' to a void type
<stdin>:1: error: 'printf' was not declared in this scope
sizeof (void)
是违反规定的。符合标准的 C 编译器(默认情况下gcc不符合)至少要警告它,并且可以(我个人认为应该)拒绝它。参考文献:N1570 6.5.3.4p1 (void
是不完整类型)。自从1989年标准引入了void
,情况一直如此。 - Keith Thompsonvoid
被引入,并且此标准还将sizeof(void)
视为一种约束违规。因此,@unixman83所说的话是不合理的。请注意,void
在此之前并不存在。 - Keith Thompson虽然 void
可以代表一种类型,但它实际上不能保存任何值。因此,在内存中它没有大小可言。获取 void
的大小是没有定义的。
void
指针 仅仅是一种语言结构,意味着一个指向 未命名 内存的指针。
void
是否可以占用内存的问题的关键。这个问题的出现是基于对C++原则的void * p
解释,导致得出结论:p
指向void
类型的内存位置,这是错误的! - Naghivoid
没有大小。在C和C++中,表达式sizeof(void)
都是无效的。
在C语言中,引用N1570 6.5.3.4第1段:
sizeof
运算符不得应用于具有函数类型或不完整类型的表达式、该类型的带括号名称或指定位域成员的表达式。
(N1570是2011年ISO C标准的草案。)
void
是不完整类型。这一段是一个约束条件,意味着任何符合C编译器必须诊断它的任何违规行为。(诊断信息可以是非致命警告。)
void
是不完整的类型,不能应用sizeof
的规则正好回溯到void
被引入语言的时候。sizeof (void)
视为1。默认情况下,gcc不是符合C编译器,因此在其默认模式下,它不会警告sizeof (void)
。即使对于完全符合C编译器,也允许使用此类扩展程序,但仍然需要进行诊断。sizeof(void) == 1
是为了与 void
指针上的指针算术保持一致,这也是 gcc 扩展。引用他们的文档:其结果是 sizeof 也可以用于 void 和函数类型,并返回 1。
。但是,由于标准要求,C 应默认提供诊断消息。 - Grzegorz Szpetkowskisizeof()
不能应用于不完整类型。而 void
是无法完成的不完整类型。
在C语言中,在GCC编译器中,sizeof(void) == 1
,但这似乎取决于你的编译器。
在C++中,我得到以下结果:
在函数'int main()'中: 第二行:错误:void类型不能使用'sizeof' 由于-Wfatal-errors,编译终止。
T*
的指针在递增时都会加上 sizeof(T)
(而不是 sizeof(T*)
,后者几乎总是相同的,除了 或许 函数指针)。当它被递增时,唯一的例外当然是 void
(再次例外的情况是启用了GCC扩展功能)。 - Konrad Rudolphvoid*
指针所指向的数据大小为 1 字节的结论的?sizeof(void)
是一个约束违规。(GCC 扩展将其视为 1。) - Keith Thompson虽然 sizeof(void) 本身可能没有意义,但在进行任何指针运算时非常重要。
例如:
void *p;
while(...)
p++;
char
也不能保证是1个字节。我曾经在一个将其设置为32位的系统上工作过。 - ashchar
保证是1个字节。如果您曾在带有32位char
的系统上工作,则该系统上的字节为32位(CHAR_BIT == 32
)。这就是C标准定义“byte”的方式。C标准,6.5.3.4的第2和第4段:“**sizeof
运算符返回其操作数的大小(以字节为单位)。[...]当sizeof
应用于具有类型 char
,unsigned char
或signed char
**(或其有资格的版本)的操作数时,结果为1。” - Keith Thompson大多数C++编译器选择在尝试获取sizeof(void)
时引发编译错误。
在编译C时,gcc不符合标准,并选择将sizeof(void)
定义为1。这看起来很奇怪,但有一个原理。当进行指针算术运算并添加或移除一个单位时,意味着添加或移除所指向对象的大小。因此,将sizeof(void)
定义为1有助于将void*
定义为指向字节(未类型化的内存地址)的指针。否则,使用指针算术运算时会出现令人惊讶的行为,例如p + 1 == p
,其中p是void*
。虽然在c++中不允许对void指针进行这样的指针算术运算,但在使用gcc编译C时可以正常工作。
标准推荐的方法是使用char*
来实现这种目的(指向字节的指针)。
C和C++在使用sizeof
时存在另一个类似的差异,当您定义一个空结构体时:
struct Empty {
} empty;
我使用gcc作为我的C编译器,sizeof(empty)
返回0。但是使用g++相同的代码将返回1。
我不确定C和C++标准在这一点上的规定,但我认为定义一些空结构/对象的大小有助于引用管理,以避免两个引用到不同连续对象(第一个为空)获得相同的地址。如果引用使用隐藏指针实现,如常所做的那样,确保不同的地址将有助于比较它们。
但这只是通过引入另一个问题(即空对象,即使是POD也会占用至少1字节的内存)来避免令人惊讶的行为(角落情况下引用的比较)。
struct
定义是语法错误;gcc的支持是一种扩展。它们可能在C++中是有效的,但我不确定。 - Keith Thompson
sizeof(void)
调用未定义行为。未定义行为是指在使用非可移植或错误的程序结构或错误的数据时,标准C没有强制限制的行为。它允许编译器做任何它选择的事情。可以将表达式评估为1(这是GCC的做法),抛出编译时错误,甚至让恶魔从你的鼻子里飞出来。 - undefined