深入理解 C/C++ sizeof() 运算符
过去有一段时间一直以为带个括号的 \(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() 运算符的更多相关文章
- 深入理解类成员函数的调用规则(理解成员函数的内存为什么不会反映在sizeof运算符上、类的静态绑定与动态绑定、虚函数表)
本文转载自:http://blog.51cto.com/9291927/2148695 总结: 一.成员函数的内存为什么不会反映在sizeof运算符上? 成员函数可以被看作是类 ...
- C++(十五) — sizeof 运算符
1.基本数据类型 sizeof 是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小. sizeof 运算符可用于获取类.结构.共用体和其他用户自定义数据类型的大小. 使用 sizeo ...
- C++ sizeof 运算符
sizeof 是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小. sizeof 运算符可用于获取类.结构.共用体和其他用户自定义数据类型的大小. 使用 sizeof 的语法如下: ...
- Sizeof运算符小结
以下内容援引自<C Primer Plus>中文版第五版Page95 Sizeof运算符以字节为单位返回其操作数的大小.(在C中,1个字节被定义为char类型所占用空间的大小.在过去,1个 ...
- sizeof运算符和strlen函数的区别
1.sizeof是运算符,而strlen是函数. 2.sizeof操作符的运算结果为size_t,他在头文件中的typedef为unsigned int.该类型保证能容纳所操作对象的最大字节大小. 3 ...
- 坑爹系列:sizeof运算符
C语言里的sizeof关键字用于返回变量的类型宽度(变量所占的字节个数).例如: #include <stdio.h> int main() { int i = 0; int size = ...
- sizeof运算符来获取各种数据类型在内存中所占字节数--gyy整理
C++并没有规定各种数据类型在内存中的存储大小,依赖于不同的编译器的不同而不同,要想获知当前编译器对各种数据类型分配的大小,可以通过sizeof运算符来获取. 使用方法1: sizeof(数据类型) ...
- sizeof运算符
sizeof运算符返回一条表达式或一个类型名字所占的字节数.sizeof运算符满足右结合律,其所得的值是一个size_t类型的常量表达式.运算符的运算对象有两种形式: sizeof(type) siz ...
- C++ Prime:sizeof运算符
sizeof运算符的结果部分地依赖于其作用的类型: 对char或者类型为char的表达式执行sizeof运算结果得1: 对引用类型执行sizeof运算得到被引用对象所占空间的大小: 对指针执行size ...
随机推荐
- Flink 1.10 正式发布!——与Blink集成完成,集成Hive,K8S
Apache Flink社区宣布Flink 1.10.0正式发布! 本次Release版本修复1.2K个问题,对Flink作业的整体性能和稳定性做了重大改进,同时增加了对K8S,Python的支持. ...
- 文件传输基础----Java IO流
编码问题 一个很著名的奇怪现象:当你在 windows 的记事本里新建一个文件,输入"联通"两个字之后,保存,关闭,然后再次打开,你会发现这两个字已经消失了,代之的是几个乱码!呵呵 ...
- MySQL学习笔记——基础与进阶篇
目录 一.###MySQL登录和退出 二.###MySQL常用命令 三.###MySQL语法规范 四.###基础查询 五.###条件查询 六.###排序查询 七.###常见函数的学习 八.###分组查 ...
- Codeforces 1060C Maximum Subrectangle(子矩阵+预处理)
题意:给出数组a,b,组成矩阵c,其中$c_{ij}=a_i*b_j$,找出最的大子矩阵,使得矩阵元素和<=x,求这个矩阵的size n,m<=2000 思路:对于子矩阵(l1...r1) ...
- num10---适配器模式
1.类适配器 Adapter类,通过继承 被适配的类,实现目标类的接口,完成适配. 分析: java 单继承,所以适配器类 需要继承 被适配类,这就要求目标类必须是接口,有一定局限性. 被适配类的方法 ...
- Golang定时任务简单实现
下载cron包: go get github.com/robfig/cron 开启一个定时: 根据cron表达式进行时间调度,cron可以精确到秒,大部分表达式格式也是从秒开始. c := cron. ...
- 编译生成protobuf的jar包
编译生成protobuf的jar包 配置maven 安装maven,并修改maven源为阿里云 下载maven wget http://mirror.bit.edu.cn/apache/maven/m ...
- CNN卷积神经网络入门整合(科普向)
这是一篇关于CNN入门知识的博客,基本手法是抄.删.改.查,就算是自己的一个笔记吧,以后忘了多看看. 1.边界检测示例假如你有一张如下的图像,你想让计算机搞清楚图像上有什么物体,你可以做的事情是检 ...
- 基于MATLAB的单级倒立摆仿真
有关代码及word文档请关注公众号“浮光倾云”,后台回复A010.02即可获取 一.单级倒立摆概述 倒立摆是处于倒置不稳定状态,人为控制使其处于动态平衡的一种摆,是一类典型的快速.多变量.非线性.强耦 ...
- 3803 register initialization
wim寄存器 window invalid mask,窗口无效屏蔽寄存器,如果某bit为1,则表示该窗口无效,不能使用. 初始化,设置%psr.CWP=0,即当前使用win0:设置wim=2,即只有w ...