计算字节相关

这类东西好像面试没遇到过,但笔试喜欢考,总结一下

32位 64位
bool 1 1
char 1 1
short 2 2
int 4 4
long 4 4/8
float 4 4
double 8 8
long long 8 8
指针 4 8
1
sizeof(string) =32

关于sizeof函数

头文件< iostream >

sizeof 是在编译的时候,查找符号表,判断类型,然后根据基础类型来取值

如果 sizeof 运算符的参数是一个不定长数组,则该需要在运行时计算数组长度

sizeof和strlen

笔试很喜欢问这个东西

1
2
3
4
5
6
7
8
char arr[20] = "hello";
cout << sizeof(arr) << endl; // warning: 'sizeof' on array function parameter 'arr' will return size of 'char*' .
cout << strlen(arr) << endl;
/*
输出结果:
8
5
*/

若字符数组 arr 作为函数的形参,sizeof(arr) 中 arr 被当作字符指针来处理,strlen(arr) 中 arr 依然是字符数组

strlen 本身是库函数,因此在程序运行过程中,计算长度;而 sizeof 在编译时,计算长度;

sizeof是c++中的运算符,它 的参数可以是类型,也可以是变量;strlen 的参数必须是 char* 类型的变量

内存对齐

编译器将程序中的每个 “数据单元” 安排在字的整数倍的地址指向的内存之中(数据的首地址为某个数k,通常为4或8的倍数)

vs中使用#pragma pack(n) 指定编译器按照n个字节对齐

**内存对齐的原则: **

结构体变量的首地址能够被其最宽基本类型成员大小对齐基数中的较小者所整除;
结构体每个成员相对于结构体首地址的偏移量 (offset) 都是该成员大小与对齐基数中的较小者的整数倍,如有需要编译器会在成员之间加上填充字节 (internal padding);
结构体的总大小为结构体最宽基本类型成员大小与对齐基数中的较小者的整数倍,如有需要编译器会在最末一个成员之后加上填充字节 (trailing padding)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
说明:程序是在 64 位编译器下测试的
*/
#include <iostream>

using namespace std;

struct A
{
short var; // 2 字节
int var1; // 8 字节 (内存对齐原则:填充 2 个字节) 2 (short) + 2 (填充) + 4 (int)= 8
long var2; // 12 字节 8 + 4 (long) = 12
char var3; // 16 字节 (内存对齐原则:填充 3 个字节)12 + 1 (char) + 3 (填充) = 16
string s; // 48 字节 16 + 32 (string) = 48
};

int main()
{
short var;
int var1;
long var2;
char var3;
string s;
A ex1;
cout << sizeof(var) << endl; // 2 short
cout << sizeof(var1) << endl; // 4 int
cout << sizeof(var2) << endl; // 4 long
cout << sizeof(var3) << endl; // 1 char
cout << sizeof(s) << endl; // 32 string
cout << sizeof(ex1) << endl; // 48 struct
return 0;
}

string 不是基本类型,所以按4对齐

进行内存对齐的原因:(主要是硬件设备方面的问题)

某些硬件设备只能存取对齐数据,存取非对齐的数据可能会引发异常
某些硬件设备不能保证在存取非对齐数据的时候的操作是原子操作
相比于存取对齐的数据,存取非对齐的数据需要花费更多的时间
某些处理器虽然支持非对齐数据的访问,但会引发对齐陷阱(alignment trap);
某些硬件设备只支持简单数据指令非对齐存取,不支持复杂数据指令的非对齐存取

内存对齐的优点:

便于在不同的平台之间进行移植,因为有些硬件平台不能够支持任意地址的数据访问,只能在某些地址处取某些特定的数据,否则会抛出异常;
提高内存的访问效率,因为 CPU 在读取内存时,是一块一块的读取。

计算类的大小

计算原则:

遵循结构体的对齐原则。

与普通成员变量有关,与成员函数和静态成员无关。即普通成员函数,静态成员函数,静态数据成员,静态常量数据成员均对类的大小无影响。因为静态数据成员被类的对象共享,并不属于哪个具体的对象。

虚函数对类的大小有影响,是因为虚函数表指针的影响

虚函数的个数并不影响所占内存的大小,因为类对象的内存中只保存了指向虚函数表的指针(8个字节)

虚继承对类的大小有影响,是因为虚基表指针带来的影响

空类的大小是一个特殊情况,空类的大小为 1,当用 new 来创建一个空类的对象时,为了保证不同对象的地址不同,空类也占用存储空间。