void类型
根据ISO/IEC 9899:2018标准第6.2.5 Types节,void类型包含一组空值,是一种不完整对象类型(incomplete object type)。本文主要讨论void类型在表达式、指针、函数中的应用。
一、表达式
任何表达式被评估为void类型表达式,其值或者指示符将被丢弃。void类型表达式评估的意义在于其副作用,例如:逗号运算符的左操作数、调用没有返回值的函数等。
a = 5, b = 6;
其中左操作数a = 5认为是一个void类型表达式。
assert(i < 0); // void类型表达式。 rewind(pFile); // void类型表达式。
其中宏assert为void类型的函数式宏,函数rewind为返回类型为void类型的函数。
(void)类型转换用于表达式时可以显式地表示丢弃表达式的值,例如:
(void)printf("Hello World!\n");
上述语句中printf函数的返回值为13,使用(void)类型转换可以显式地告诉编译器丢弃这个返回值。
此外ISO/IEC 9899:2018标准第6.3.2.2 void节还规定:不能以任何方式使用void类型表达式的值,并且不能对此类表达式使用隐式类型转换或者显式类型转换(void除外)。
二、指针
void类型指针也称为通用指针。void类型指针可以转换为指向任何对象类型的指针;指向对象类型的指针也可以转换为void类型指针。指向对象类型的指针转换为void类型指针,再从void类型指针转换为指向对象类型的指针,结果应与原始指针相等。void类型指针未与任何数据类型相关联,可以保存任何对象类型的地址。
int a = 3; float b = 3.14f; void *ptr = NULL; ptr = &a; //void类型指针保存int类型对象地址。 ptr = &b; //void类型指针保存float类型对象地址。
其中void类型指针ptr既能保存int类型对象的地址,也能保存float类型对象的地址;这与int类型指针只能保存int类型对象的地址、float类型指针只能保存float类型对象的地址不同。
void类型指针用于函数声明时,如果用于函数的返回类型,则表示返回一个通用指针,例如:内存分配函数;
void *calloc(size_t nmemb, size_t size); void *malloc(size_t size); void *realloc(void *ptr, size_t size);
上述例子分配的内存适用于各种数据。
如果void类型指针用于函数参数,则表示函数可以使用各种类型的指针参数,例如:qsort函数中的比较函数。qsort函数的函数原型为:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
应用范例:
|
|
上述代码将输出:
The order of arrInt:
-5 0 3 10 25
The order of arrFloat:
3.14 7.26 10.33 47.25 88.88 96.32
在这个例子中,分别使用int类型的指针参数和float类型的指针参数作为比较函数的参数。
使用void类型指针有两点需要注意:
1、ISO/IEC 9899:2018标准禁止使用void类型指针进行算术运算,详细请参阅标准第6.5.6 Additive operators节,标准要求算术运算的指针应为指向完整对象类型的指针。实现中一些编译器可能允许void类型指针进行算术运算。
2、void类型指针无法解除引用。
float a = 3.14f; void *ptr = NULL; ptr = &a; printf("%.2f\n", *ptr); //编译时会出错。
上述代码编译时,编译器会给出类似error: invalid use of void expression的出错信息,因为编译器不知道void类型指针指向对象的实际类型。
如果使用下述语句一切都正常了。
printf("%.2f\n", *(float *)ptr);
三、函数
void类型用于函数声明时,如果用于函数的返回类型,则表示函数没有返回值,例如:setbuf、rewind、clearerr等函数,其函数原型分别如下所示:
void setbuf(FILE * restrict stream, char * restrict buf); void rewind(FILE *stream); void clearerr(FILE *stream);
如果void类型用于函数参数,则表示该函数没有参数,例如:rand、abort、clock等函数,其函数原型分别如下所示:
int rand(void); _Noreturn void abort(void); clock_t clock(void);
应用范例:
|
|
上述代码将输出:
Quality matters more than quantity.
Hello World!
其中printMessage函数是没有返回值的函数;printHello函数是既没有参数,也没有返回值的函数。