过去有一段时间一直以为带个括号的 \(sizeof()\) 是 \(C/C++\) 的原生函数QAQ。

其实不然,\(sizeof\) 同位运算符(^|&~!)一样是一种单目运算符,作用于变量或数组。

在编译时编译器就会把 \(sizeof()\) 的内容转换成常数存入机器码中,不涉及函数的底层操作。

用途

sizeof 运算符可用于获取类、结构、共用体和其他用户自定义数据类型的大小。

使用 sizeof 的语法如下:

sizeof (data type)

其中,data type 是要计算大小的数据类型,包括类、结构、共用体和其他用户自定义数据类型。

sizeof 与 普通变量

#include<bits/stdc++.h>
using namespace std;
int main() {
char char_var;
float float_var;
double double_var;
long double ldouble_var;
int int_var;
long long ll_var; printf("sizeof char = %d\n",sizeof(char_var));
printf("sizeof float = %d\n",sizeof(float_var));
printf("sizeof double = %d\n",sizeof(double_var));
printf("sizeof long double = %d\n",sizeof(ldouble_var));
printf("sizeof int = %d\n",sizeof(int_var));
printf("sizeof long long = %d\n",sizeof(ll_var));
return 0;
}

输出结果:

sizeof char = 1
sizeof float = 4
sizeof double = 8
sizeof long double = 16
sizeof int = 4
sizeof long long = 8

可以看出,编译器把 sizeof 的内容都替换成了变量占用的空间大小(单位为字节)。

此外,作为一个运算符,在 sizeof 之后的变量名可以不用括号括起来,这样在概念上就不会和函数混淆了。

sizeof 与 指针变量

#include<bits/stdc++.h>
using namespace std;
int main() {
char *char_point;
double *double_point;
int *int_point;
long long ll_point; printf("sizeof pchar = %d\n",sizeof(char_point));
printf("sizeof pdouble = %d\n",sizeof(double_point));
printf("sizeof pint = %d\n",sizeof(int_point));
printf("sizeof plong long = %d\n",sizeof(ll_point));
return 0;
}

输出结果:

sizeof pchar = 8
sizeof pdouble = 8
sizeof pint = 8
sizeof plong long = 8

所有类型的指针变量在 \(32\) 位环境中占用四字节,在 \(64\) 位环境中占用 \(8\) 字节。

我的编译器是 \(x64\)( \(64\) 位)的,如果是 \(x86\) 编译器( \(32\) 位)下输出结果应该是 \(4\) 。

sizeof 与 数组

#include<bits/stdc++.h>
using namespace std;
int main() {
char char_arr[10]="233";
double double_arr[10]={0.0};
int int_arr[10]={0,1,2,3,4,5,6,7,8,9};
long long ll_arr[10]; printf("sizeof arrchar = %d\n",sizeof(char_arr));
printf("sizeof arrdouble = %d\n",sizeof(double_arr));
printf("sizeof arrint = %d\n",sizeof(int_arr));
printf("sizeof arrlong long = %d\n",sizeof(ll_arr));
return 0;
}

输出结果:

sizeof arrchar = 10
sizeof arrdouble = 80
sizeof arrint = 40
sizeof arrlong long = 80

sizeof 与结构体

#include<bits/stdc++.h>
using namespace std;
int main() {
struct Student {
char name[20];
bool sex;
int age;
int num;
}stu; printf("sizeof (Student)stu = %d\n",sizeof(stu));
return 0;
}

输出结果:

sizeof (Student)stu = 32

name数组占用 \(1*10=20\) 个字节,两个int占用 \(4*2=8\) 个字节,一个bool占用 \(1\) 个字节,加起来应该是 \(29\) 。

而程序输出了 \(32\) ,是不是编译器出问题了?

其实这是正常的,因为结构体的成员变量占用的是一块连续的内存,但是为了保证对不同类型的变量寻址正确,编译器会在储存各变量地址时自动对齐,而不是每个变量的内存块都紧密相连。

计算结构体大小需要了解一个名词偏移量,即结构体变量中成员的地址与结构体首地址的差(首个成员的地址),结构体内容每个成员(包括成员变量、函数、嵌套体)都拥有这一属性。

结构体内偏移量的计算公式为:上一个成员的偏移量 + 上一个成员的占用字节数

为了做到成员地址的对齐,编译器在编译程序时会遵照如下规则:

结构体变量中成员的偏移量必须是该成员大小的整数倍,否则向上补齐

还是用上面的例子,

\(name[20]\) 为首元素,偏移量为 \(0\) 。

\(sex\) 偏移量为 \(0 + 20 = 20\),\(20 \% 1 = 0\) ,无须补齐。

\(age\) 偏移量为 \(20 + 1 = 21\),\(21 \% 4 ≠ 0\),偏移量向上补齐为整除 \(4\) 的 \(24\)。

\(num\) 偏移量为 \(24 + 4 = 28\),\(28 \% 4 = 0\) ,无须补齐。

最后算出该结构体占用的内存大小为 = num的偏移量 + num占用的大小 = \(32\) 字节。

根据结构体变量地址对齐的这一特性,还可以知道在结构体中,结构体成员变量写的顺序会影响该结构体占用的空间大小。

根据简单的数学知识,把内存占用较小的结构体成员写在前面是比较优秀的

此外,结构体标准对齐值也可以自定义,具体操作可以参考这篇博客




最后,下次写 \(memset\) 的参数就可以不用写算出占用的空间而不用 \(sizeof\) 啦!(丝毫没用)

深入理解 C/C++ sizeof() 运算符的更多相关文章

  1. 深入理解类成员函数的调用规则(理解成员函数的内存为什么不会反映在sizeof运算符上、类的静态绑定与动态绑定、虚函数表)

    本文转载自:http://blog.51cto.com/9291927/2148695 总结: 一.成员函数的内存为什么不会反映在sizeof运算符上?             成员函数可以被看作是类 ...

  2. C++(十五) — sizeof 运算符

    1.基本数据类型 sizeof 是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小. sizeof 运算符可用于获取类.结构.共用体和其他用户自定义数据类型的大小. 使用 sizeo ...

  3. C++ sizeof 运算符

    sizeof 是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小. sizeof 运算符可用于获取类.结构.共用体和其他用户自定义数据类型的大小. 使用 sizeof 的语法如下: ...

  4. Sizeof运算符小结

    以下内容援引自<C Primer Plus>中文版第五版Page95 Sizeof运算符以字节为单位返回其操作数的大小.(在C中,1个字节被定义为char类型所占用空间的大小.在过去,1个 ...

  5. sizeof运算符和strlen函数的区别

    1.sizeof是运算符,而strlen是函数. 2.sizeof操作符的运算结果为size_t,他在头文件中的typedef为unsigned int.该类型保证能容纳所操作对象的最大字节大小. 3 ...

  6. 坑爹系列:sizeof运算符

    C语言里的sizeof关键字用于返回变量的类型宽度(变量所占的字节个数).例如: #include <stdio.h> int main() { int i = 0; int size = ...

  7. sizeof运算符来获取各种数据类型在内存中所占字节数--gyy整理

    C++并没有规定各种数据类型在内存中的存储大小,依赖于不同的编译器的不同而不同,要想获知当前编译器对各种数据类型分配的大小,可以通过sizeof运算符来获取. 使用方法1: sizeof(数据类型) ...

  8. sizeof运算符

    sizeof运算符返回一条表达式或一个类型名字所占的字节数.sizeof运算符满足右结合律,其所得的值是一个size_t类型的常量表达式.运算符的运算对象有两种形式: sizeof(type) siz ...

  9. C++ Prime:sizeof运算符

    sizeof运算符的结果部分地依赖于其作用的类型: 对char或者类型为char的表达式执行sizeof运算结果得1: 对引用类型执行sizeof运算得到被引用对象所占空间的大小: 对指针执行size ...

随机推荐

  1. 死磕mysql(3)

    花了一个晚上得出的结论,autocommit=1是不是立刻提交,autocommit=0是没有写入数据库的关闭数据,除非遇到commit和rollback........把自己给逗了关闭数据库发现数据 ...

  2. 如何写出优雅的Python代码?

    有时候你会看到很Cool的Python代码,你惊讶于它的简洁,它的优雅,你不由自主地赞叹:竟然还能这样写.其实,这些优雅的代码都要归功于Python的特性,只要你能掌握这些Pythonic的技巧,你一 ...

  3. Java集合XMind与注意事项

    Java中集合使用时的几个注意事项: 1.ArrayList和HashMap都具有扩容 ArrayList初始化数组长度为10,扩容后的容量为原来的1.5倍. HashMap初始化的数组长度为16,扩 ...

  4. 记一个实时Linux的中断线程化问题

    背景 有一个项目对实时性要求比较高,于是在linux内核上打了RT_PREEMPT补丁. 最终碰到的一个问题是,芯片本身性能不强,CPU资源不足,急需优化. 初步分析 看了下cpu占用率,除了主应用之 ...

  5. MongoDB疑难解析:为什么升级之后负载升高了?

    本文是"我和MongoDB的故事"征文比赛的二等奖得主李鹏冲的文章.下面我们一起来欣赏下. 问题 近期线上一个三分片集群从 3.2 版本升级到 4.0 版本以后,集群节点的 CPU ...

  6. python3 kubernetes api 使用

    一.安装 github:https://github.com/kubernetes-client/python 安装 pip install kubernetes 二.认证 1.kubeconfig文 ...

  7. 【算法总结】图论/dp-动态规划 大总结

    写于一只蹲在角落的蒟蒻-Z__X... 2020.2.7,图论和 \(dp\) 终于告一段落.蓦然回首,好似已走过许多...不曾细细品味,太多太多又绵延不断地向我涌来... 谨以此纪念 逝去 的图论和 ...

  8. leetcode--js--Median of Two Sorted Arrays

     问题描述: There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of ...

  9. linux中find文件搜索命令

    find 解释 命令名称:find 命令所在路径:/bin/find 执行权限:所有用户 功能描述:文件搜索 语法 find [搜索范围] [匹配条件] 匹配条件: -name 文件名(区分大小写) ...

  10. ASP.NET Core MVC 网站学习笔记

    ASP.NET Core MVC 网站学习笔记 魏刘宏 2020 年 2 月 17 日 最近因为” 新冠” 疫情在家办公,学习了 ASP.NET Core MVC 网站的一些知识,记录如下. 一.新建 ...