空隙的大小是多少?


76

这句话会产生什么?

void *p = malloc(sizeof(void));

编辑:问题的扩展。

如果sizeof(void)在GCC编译器中产生1,则分配1字节的内存,指针p指向该字节,p ++是否会递增为0x2346?假设p为0x2345。我说的是p,而不是* p。


4
仅供参考。这是非标准的C。在许多编译器中,这将是编译时错误。
2009年

你为什么要知道。了解这一点可能有助于我们回答问题。
马丁·约克

4
评论您的编辑:是的,在GCC中(仅),递增void指针会将值添加一个。如果您重视代码的可移植性,请不要滥用GCC给您的自由。这完全是非标准的。并且GCC接受的'-std = c99 -pedantic'也是一样。
乔纳森·莱夫勒

Answers:


55

类型void没有大小。那将是一个编译错误。出于同样的原因,您不能执行以下操作:

void n;

编辑。令我惊讶的是,sizeof(void)实际上确实可以在GNU C中进行编译:

$ 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

30
但GCC可以选择处理'sizeof(void)== sizeof(char)'...请参阅-Wpointer-arith
Jonathan Leffler,2009年

4
@Jon这是针对80年代初才开始学习编程的傻瓜的。标准尚未广泛确定。
unixman83

5
sizeof (void)是违反约束的。合格的C编译器(默认情况下,gcc并非默认)必须至少对其发出警告,并且可能(并且恕我直言应该)拒绝它。参考:N1570 6.5.3.4p1(void是不完整的类型)。自从1989年标准引入以来就是这种方式void
基思·汤普森

3
@ unixman83:那没有道理。void在1989年ANSI C标准引入之前,它就不存在了,该标准sizeof (void)违反了约束。
基思·汤普森

1
编译sizeof void是因为您需要使用它来处理void *指针。
凯林2015年

40

如果您使用的是GCC,并且没有使用删除编译器特定扩展的编译标志,sizeof(void)则为1。GCC具有执行此操作的非标准扩展

通常,void它是不完整的类型,您不能将sizeof用于不完整的类型。


2
该选项-Wpointer-arith由隐含-pedantic。我一直都习惯-pedantic。:)
Josh Lee,2009年

1
@jleedev的确,我也尽可能多地使用-pedantic。但是,不幸的是,一些第三方库头文件使gcc -pedantic非常可悲:(
hrnt

1
+1真的,为什么GCC有数千个无用的扩展名?

@ user142019:因为它们有用吗?并且有助于通过不同的编程语言和硬件体系结构获得一致的后端模型。
kriss 2014年

15

尽管void可以代替某个类型,但实际上不能保存值。因此,它在内存中没有大小。void没有确定a的大小。

一个void 指针是一个简单的语言建构意义的指针,无类型的内存。


1
所以呢 ?不应有任何空结构也不会占用内存大小,这应该是一个问题。好吧,实际上我想知道,空结构在C ++中是否真的使用0字节(在C中也是如此)看起来sizeof为它们返回1。
克里斯,

1
@kriss我不确定您在说什么,但是您已经注意到自己,由于对象标识的原因,空结构确实占用了内存。
Konrad Rudolph

1
的确如此,但是在C语言中并非如此,对空对象使用内存感觉很邪恶。
克里斯,

13

void没有大小。在C和C ++中,该表达式sizeof (void)均无效。

在C中引用N1570 6.5.3.4第1段:

sizeof操作者不得应用于具有功能类型的表达式或不完整的类型,这样的类型的括号名称,或者将指定的位字段构件的表达式。

(N1570是2011 ISO C标准的草案。)

void是不完整的类型。本段是一个约束,这意味着任何符合标准的C编译器都必须诊断出对此有任何违反。(诊断消息可能是非致命警告。)

C ++ 11标准的措辞非常相似。在问了这个问题之后,两个版本都发布了,但是规则可以追溯到1989年的ANSI C标准和最早的C ++标准。实际上,不适用void的不完全类型的规则sizeof可以追溯到void对语言的介绍。

gcc的扩展名被视为sizeof (void)1。gcc默认情况下不是兼容的C编译器,因此在其默认模式下它不会发出警告sizeof (void)。即使对于完全符合标准的C编译器,也可以使用这样的扩展名,但是仍然需要诊断。


我猜想它们允许sizeof(void) == 1与指针上的void指针算法保持一致,这也是gcc扩展。从他们的文档中引用:A consequence of this is that sizeof is also allowed on void and on function types, and returns 1.。但是默认情况下,对于C,诊断消息仍应存在,因为Standard要求它。
Grzegorz Szpetkowski

2
@GrzegorzSzpetkowski:(几年后回复。)是的,该标准需要诊断,但默认情况下gcc不是兼容的C编译器。逻辑上,C标准对不声称符合该标准的实现不施加任何要求。可以使gcc(几乎)符合正确的命令行选项,例如-std=c11 -pedantic。使用此类选项,它会发出所需的诊断信息。
基思·汤普森



3

在C中,sizeof(void) == 1在GCC中,但这似乎取决于您的编译器。

在C ++中,我得到:

在函数'int main()'中:
第2行:错误:将'sizeof'无效应用到void类型
由于-Wfatal-errors,编译终止。

3
仅在GCC中sizeof(void)== 1; 在标准中,它是未定义的行为。
乔纳森·莱夫勒

更新以添加特定于GCC的注释。
Greg Hewgill

2
@JonathanLeffler:这不仅是未定义的行为。这是违反约束的行为。N1570 6.5.3.4p1。
基思·汤普森

它不仅是GCC,而且是GCC和旨在与其兼容的任何其他编译器(包括clang,icc,tcc,可能还有其他编译器)。
基思·汤普森

0

对于问题的第二部分:请注意,sizeof(void *)!= sizeof(void)。在32位的Arch上,sizeof(void *)是4个字节,因此p ++会被相应地设置。指针的增加量取决于它所指向的数据。因此,它将增加1个字节。


1
所以p指向1字节数据,因为sizeof(void)给出1,所以p ++意味着p将增加1而不是4?
拉克希米

1
指针增加的数量取决于指针所指向的数据。是的

p是void *(无效指针)类型,不是void。因此,它会增加void *类型的大小(在32位系统中通常为4)。
Technowise

4
@Technowise:不。类型的任何指针T*被增加sizeof(T)(和 sizeof(T*),这将几乎始终是相同的,除了也许函数指针),当它被递增。当然void是例外(同样,启用了GCC扩展时也是例外)。
康拉德·鲁道夫

1
@Amit:您如何得出结论,void*指针指向的数据大小为1个字节?sizeof (void)是违反约束的。(gcc扩展名将其视为1。)
Keith Thompson

-1

虽然sizeof(void)本身可能没有任何意义,但是在进行任何指针数学运算时,这一点很重要。

例如。

 void *p;
 while(...)
      p++;

如果将sizeof(void)视为1,那么它将起作用。如果将sizeof(void)视为0,则您遇到无限循环。


4
示例代码段在C和C ++中是非法的。某些编译器仍然允许它。
James Roth 2013年

1
不,这根本不重要(尽管gcc的作者显然认为是重要的)。如果要对字节指针执行指针算术,请使用unsigned char*
基思·汤普森

@KeithThompson-甚至char不能保证为1个字节。我曾在将其设置为32位的系统上工作。

@ash:是的,char保证为1个字节。如果您使用的char是32位系统,则该系统上的一个字节为32位(CHAR_BIT == 32)。这就是C标准定义“字节”的方式。C标准,段落6.5.3.4 2和4道:“sizeof操作者产生其操作数的大小(以字节计)[...]当。sizeof被施加到具有类型的操作数charunsigned charsigned char,(或合格的版本体)结果是1。“
基思·汤普森

C标准6.5.3.4何时发布?我在90年代中期就在此系统上工作。

-1

大多数C ++编译器在尝试获取时都选择引发编译错误sizeof(void)

编译C时,gcc不符合要求sizeof(void),而是选择定义为1。它可能看起来很奇怪,但是有一定的道理。当您执行指针算术时,添加或删除一个单位表示添加或删除指向大小的对象。因此,将其定义sizeof(void)为1有助于将其定义void*为指向字节(未类型化的内存地址)的指针。否则,使用像p+1 == p whenp is这样的指针算法会产生令人惊讶的行为void*。在C ++中不允许在void指针上使用此类指针算术,但在使用gcc编译C时可以很好地工作。

推荐的标准方法是char*用于这种目的(指向字节的指针)。

使用sizeof时,C和C ++之间的另一个类似区别发生在您定义空结构时,例如:

struct Empty {
} empty;

使用gcc作为我的C编译器sizeof(empty)将返回0。使用g ++相同的代码将返回1。

我不确定在这一点上什么同时说明了C和C ++标准,但是我相信定义一些空结构/对象的大小有助于引用管理,从而避免两个对不同连续对象的引用,第一个为空,得到相同的地址。如果引用是经常使用隐藏指针实现的,则确保不同的地址将有助于比较它们。

但这只是通过引入另一个对象(空对象,甚至POD占用至少1个字节的内存)来避免令人惊讶的行为(对引用进行角落情况比较)。


6
“ C而是选择将sizeof(void)定义为1。” –不,那是错的。sizeof(void)与C ++中一样,没有在C中定义。在这一点上,GCC根本不符合要求,并且指针上的指针算法void也没有定义,这void* p; p++;是无效的。使用该-pedantic标志编译时,即使是GCC也会给您警告。您还错了GCC for C ++的默认行为:默认情况下,这被视为error
Konrad Rudolph

@Konrad:是的,我敢肯定,较旧版本的gcc并非如此,但最新的版本确实可以做到。
克里斯,

至少在C语言中,空struct定义是语法错误;gcc的支持是扩展。它们可能在C ++中有效。我不确定。
基思·汤普森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.