深入理解 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 ...
随机推荐
- 在Mysql中,事务是如何实现的呢?
hello大家好,我是一个爱看底层的小码,对于每一个学习mysql数据库的同学来说,事务都是一个绕不开的话题,简单的说来事务是指访问并可能更新数据库中各项数据项的一个程序执行单元.事务的四个特征无非就 ...
- excel 2010 如何设置日期选择器
excel 中想输入很多的日期.如果每个日期都直接手动输入太过于繁琐,而且容易出错.想制作一个日期选择器,直接鼠标点选就可以了. 效果如下: 具体实现参考 http://wenku.baidu.com ...
- Codeforces_739_B
http://codeforces.com/problemset/problem/739/B dfs,记录距离前缀和,每次找到离最近的不符合的点. #include<iostream> # ...
- lua学习之基础概念篇
基础概念 程序块 (chunk) 定义 lua 中的每一个源代码文件或在交互模式(Cmd)中输入的一行代码都称之为程序块 一个程序块就是一连串语句或者命令 lua 中连续的语句不需要分隔符,但为了可读 ...
- 一文读懂什么是一致性hash算法
Hash,一般翻译做散列.杂凑,或音译为哈希,是把任意长度的输入通过散列算法变换成固定长度的输出,该输出就是散列值.这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入值的空间,不同的输入可能会 ...
- node - 简单的爬虫案例
cherrio模块 安装 cnpm install cherrio 使用方法 const cheerio = require('cheerio') const $ = cheerio.load('&l ...
- JAVA SOCKET多线程等待接受客户端信息实现
服务端程序: public class Demo { public static void main(String[] args) { // TODO 自动生成的方法存根 try { ServerSo ...
- OSPF配置实验(一)
单区域OSPF 命令: R1(config)#router ospf 1 //启动OSPF进程 R1(config-router)#router-id 1.1.1.1 // ...
- 杭电-------2055An Easy Problem(C语言)
#include<stdio.h> int main() { int m; int i; scanf("%d", &m); ]; int y; int z; ; ...
- h5笔记1
1.HTML中不支持 空格.回车.制表符,它们都会被解析成一个空白字符 2.适用于大多数 HTML 元素的属性: class 为html元素定义一个或多个类名(classname)(类名从样式文件引入 ...