C语言sizeof宏分析
本文主要介绍C语言中sizeof的原理分析
原理
sizeof 是 C 语言的一个运算符,用于返回一个对象或数据类型的大小,以字节为单位。sizeof 运算符在编译时计算,不会执行实际的运算。
由于 sizeof 是编译时计算大小的,其实现是由编译器提供的,而不是由标准 C 库提供的函数。因此,sizeof 的实现通常依赖于编译器和目标体系结构。
实现方式
以下是 sizeof 运算符的一种可能的简化实现,假设一个字节等于 8 比特:
test.c文件
#define SIZEOF(type) ((size_t)(&((type*)0)[1]))
// 示例用法
int main() {
size_t size = SIZEOF(int);
return 0;
}这个宏的工作原理是,将一个空指针转换为类型 type*,然后取数组的第一个元素的地址。由于数组索引是从零开始的,&((type*)0)[1] 计算出第一个元素之后的地址。然后,整个表达式被强制转换为 size_t 类型,以表示大小。
需要注意的是,这只是一个简化的例子,实际的实现可能更为复杂,以处理各种类型和体系结构。实际的 sizeof 实现通常是由编译器内部提供的,因为它需要考虑各种编译器和目标平台的特定细节。
代码分析
(size_t)(&((type*)0)[1]) 的运算顺序可以分解为以下步骤:
(type*)0: 将整数 0 转换为指向类型type的指针,得到一个指向类型type的空指针。((type*)0)[1]: 使用上一步得到的空指针进行数组操作,取得数组的第二个元素。这等效于( ((type*)0) + 1)。请注意,这里并没有实际的数组,只是利用了指针运算的语法。&((type*)0)[1]: 取得数组第二个元素的地址。(size_t)(&((type*)0)[1]): 将这个地址转换为size_t类型。
整个表达式的目的是计算一个指向类型 type 的指针,指向一个虚构的数组的第二个元素,然后获取这个元素的地址,并将其转换为 size_t 类型。这种技巧通常用于计算结构体或数组的大小,而无需创建实际的实例。
通过将test.c文件编译成汇编文件可发现:
SIZEOF(int) 对应汇编文件中的 movq $4, -8(%rbp),将值 4 存储在相对于 %rbp 偏移为 -8 的位置。
SIZEOF(double) 对应汇编文件中的movq $8, -8(%rbp),将值 8 存储在相对于 %rbp 偏移为 -8 的位置。
可见将整数 0 转换为指向类型 type 的指针,得到一个指向类型 type 的空指针时type[0]的地址为0,((type*)0)[1]的偏移量即为type的字节大小,从而可获取type的字节大小
