在C语言中,void是一种数据类型吗?

70

void在C编程语言中算不上一种数据类型。它不能存储任何值。与用来存储值的int, float, char等数据类型不同,void通常用于表示函数返回值为空,或作为指针类型中没有特定类型的通用指针。因此,范围是不确定的。


3
它毫无用处,甚至不是原始的K&R pre-ansi C的一部分。一些白痴认为 myFunction() { /* ... */ } 看起来太整洁了,就不得不添加一些无意义的 void myFunction(void) { /* ... */ } - 我认为如果你无法忍受使用 char *,还有其他更清晰的选项,这是在void出现之前声明“通用”指针的常见方式。 - Christoffer Bubach
2
@ChristofferBubach 但在C语言中,function(void)并不等同于function(),因为在前者中你可以完全不传递参数,而在后者中你可以传递任何参数:https://www.geeksforgeeks.org/difference-int-main-int-mainvoid (除了C++,在C++中两者都表示函数不接受任何参数) - Edw590
我认为任何C编译器都能够轻松检测参数使用或外部链接,以便使用最有效的调用入口点。使用“…”来清楚地指示未知数量的参数或新的可变参数类型的反向语法会更加简洁,仍然允许在只声明空括号时进行自动检测。这基本上就是新代码的外观,那么为什么还要添加void呢?编译器真的在保留符号及其使用方面如此糟糕吗? - Christoffer Bubach
3个回答

103

Void被视为一种数据类型(出于组织目的),但基本上它只是一个关键字,用作占位符,代表“没有数据”,您可以在其中放置一个数据类型。

因此,您可以声明一个不返回值的例程如下:

void MyRoutine();

但是,你不能像这样声明一个变量:

void bad_variable;

然而,当用作指针时,它有不同的含义:

void* vague_pointer;

这声明了一个指针,但没有指定它所指向的数据类型。


18
由于你没有指定一个空指针指向什么,所以你无法对其进行数学运算。编译器无法确定移动指针多远才能到达内存中的下一项。 - user240438
6
void MyRoutine();是一种旧式(K&R C)函数声明,在C99中已被弃用,不是原型。应该用void MyRoutine(void);代替。 - Jens
6
如果您使用支持该特性的gcc编译器,可以对void*类型的值执行算术运算,gcc通过假装sizeof(void) == 1来支持这种扩展。 (个人认为这很不幸。) - Keith Thompson
1
以下定义可以正常工作:extern void foo; - Sven
3
@AnT:一个不完整的结构体类型并没有全部void类型具有相同的属性。它们都是不完整的类型,但例如所有指向结构体类型的指针具有相同的表示方式;void *可能具有相同的表示方式,也可能没有。此外,不完整的结构体类型可以被完整定义;而void则不能。 - Keith Thompson
显示剩余19条评论

36

是的,void 是一种类型。它是否是数据类型取决于您如何定义该术语;C标准没有确定。

C标准定义了"对象类型"这个术语。在C99和之前版本中,void 不是对象类型;在C11中,它是对象类型。在所有版本的标准中,void 是不完整类型。在C11中改变的是不完整类型现在是对象类型的一个子集;这只是一个术语上的变化。(另一种类型是函数类型。)

C99第6.2.6段第19条说:

void类型包括一个空值集;它是一个不完整类型,无法完成。

C11标准稍微更改了措辞:

void类型包括一个空值集;它是一个不完整的对象类型,无法完成。

这反映了C11中"对象类型"的定义变化,包括不完整类型;它并没有真正改变类型void的本质。

void关键字也可以在其他一些上下文中使用:

  • 在函数原型中作为唯一的参数类型,如int func(void),表示该函数没有参数。 (C ++使用空括号表示此内容,但在C中它们表示其他内容。)

  • 作为函数的返回类型,如void func(int n),表示该函数不返回结果。

  • void*是一种指针类型,不指定它指向什么。

原则上,所有这些用法都涉及类型 void,但您也可以将它们视为只是使用相同关键字的特殊语法。


int func()和int void()之间有什么区别? - funky-nd
4
再次查看您的问题,我怀疑您想问的是 int func()int func(void) 之间的区别。区别在于后者是一个原型,它指定该函数不带任何参数。前者是旧式的函数声明,不指定函数预期的参数。(很少有好的理由使用旧式的函数声明。) - Keith Thompson

8

C标准规定void是一种无法完成的不完整类型(与其他可以完成的不完整类型不同)。这意味着您不能对void应用sizeof运算符,但可以拥有指向不完整类型的指针。


考虑 extern void x;。1)如果 x 可以在“C 之外”完成(例如在汇编中),那么为什么 &x 是无效的?2)是否存在对 x 的有效操作? - pmor
@pmor 如果完成发生在“C之外”,那意味着编译器不知道它。&x 不是无效的,void x 以及其后面的所有内容都是无效的。至于第二点,应该有两个 void x 分配给 void y 的情况,但是由于编译器不知道 x 和 y 的大小,所以这是不可能的。 - Jens
我的意思是 "&x 在这种情况下是无效的(即如果 x 声明为 extern void x;)"。 - pmor
无论是Clang还是GCC,在-std=c11 -pedantic -Wall -Wextra下都接受extern const void x; const void* p = &x;。这段代码有效吗?如果无效,那么为什么Clang和GCC决定接受它呢? - pmor
@pmor 是的,这段代码是有效的。指定一个 <type-qualifier> void 类型对象(例如 const void)的表达式是左值。 - pmor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接