sizeof(void)之谜

科技   2024-10-14 08:51   浙江  

在 C 和 C++ 中,void 类型和 sizeof 运算符是每位程序员都应掌握的基本概念。然而,sizeof(void) 的概念可能会让人感到困惑,特别是对于这些语言的新手来说。本文将解释 void 是什么,为什么 sizeof(void) 在传统意义上没有意义,以及这些概念在实际编程中的应用。

什么是void?

在 C 和 C++ 中,void是用于表示不存在任何类型的关键字。它通常用于三种场景。

函数

当某个函数的返回值被声明为void,即意味着该函数不返回任何内容,那么获取函数返回内容的操作将是非法或者未定义的行为。

void Print() {
  std::cout << "Hello world!!!" << std::endl;
}

在这个函数中,只有一行输出操作,不返回任何类型。

空指针

空指针voidvoid *) 是一种特殊类型的指针,可以指向任何数据类型。但是,由于未指定类型,因此在解引用之前必须将其转换为适当的类型。

void* ptr;
int num = 42;
ptr = &num; // void 指针可以指向 int 类型的地址

int* intPtr = (int*)ptr; // 需要将 void 指针转换为具体类型

函数参数

相信很多从事C开发的人,经常会见到形如fun(void)这种代码,在这种代码中,void作为函数参数的意思是该函数没有参数,或者说指定函数不接受任何参数,与fun()等同,不过这种写法现在已经很少见了~

void fun(void) {
    // 函数体
}

sizeof操作符

在 C++ 中,sizeof 操作符是一个编译时运算符,用于获取数据类型或对象的内存大小。它是一个非常重要的工具,可以帮助程序员了解变量、类型或数据结构的内存占用情况。

int x = 10;
printf("size of int: %d bytes\n"sizeof(int));
printf("size of x: %d bytes\n"sizeof(x));

sizeof(void)

好了,前面的一系列铺垫,就是为了引入本节主题。

对于这种问题,我一般会先在本地编码试试。

// size.c

#include <stdio.h>

int main() {
  printf("sizeof void is %d bytes\n"sizeof(void));

  return 0;
}

以及

// size.cc

#include <iostream>

int main() {
  std::cout << "sizeof void is: " << sizeof(void) << std::endl;

  return 0;
}

对于size.c,尝试使用gcc和clang进行编译:

clang size.c -o size // clang
gcc size.c -o size // gcc

输出都是

sizeof void is 1 bytes

但是,对于size.cc即对于c++版本的,g++可以编译通过,输出同c版本,而clang++则编译失败,输出如下:

size.cc:4:38: error: invalid application of 'sizeof' to an incomplete type 'void'
    4 |   std::cout << "sizeof void is: " << sizeof(void) << std::endl;
      |                                      ^     ~~~~~~
1 error generated.

说实话,看到编译和运行结果的时候,我是一脸懵的,完全出乎了我的意料~

针对上面的结果,看了某些资料,偶然翻到了标准对这块的回复(ISO/IEC 9899:2011):

The sizeof operator shall not be applied to an expression that has function type or an incomplete type, to the parenthesized name of such a type, or to an expression that designates a bit-field member.

意思是sizeof 操作符不得应用于以下情况的表达式:

函数类型的表达式不完整类型的表达式这种类型的带括号的名称指定位域成员的表达式

以及:

The void type comprises an empty set of values; it is an incomplete object type that cannot be completed.

意思是void是一个不完整类型,那么问题来了,既然标准都说了void是一个不完整类型,那么gcc为什么输出为1呢?

针对这个问题,继续查资料,得到回复如下:

In GNU C, addition and subtraction operations are supported on pointers to void and on pointers to functions. This is done by treating the size of a void or of a function as 1.

A consequence of this is that sizeof is also allowed on void and on function types, and returns 1.

The option -Wpointer-arith requests a warning if these extensions are used.

意思是,在 GNU C中,指向 void 指针和指向函数的指针支持加法和减法操作。这是通过将 void 或函数的大小视为1来实现的。

因此,sizeof 操作符也可以用于 void 和函数类型,并返回 1。选项 -Wpointer-arith 会在使用这些扩展时发出警告。

推荐阅读  点击标题可跳转

1、细说进程为什么需要睡眠?

2、手撸一个内存分配器

3、C++发布革命性提案:“借鉴”Rust精华,内存安全即将成为标配?

CPP开发者
我们在 Github 维护着 9000+ star 的C语言/C++开发资源。日常分享 C语言 和 C++ 开发相关技术文章,每篇文章都经过精心筛选,一篇文章讲透一个知识点,让读者读有所获~
 最新文章