一般使用sizeof判断struct所占的字节数,那么计算规则是什么呢?
关键词:
1.变量的起始地址和变量自身的字节数
2.以最大变量字节数进行字节对齐(倍数关系)。
注:这里介绍的原则都是在没有#pragma pack宏的情况下
先举个例子:
struct A
{
char a[5];
int b;
short int c;
}struct A;
在上例中,要计算 sizeof(a) 是多少?
有两个原则:
1)各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数
即当 A中的a占用了5个字节后,b需要占用四个字节,此时如果b直接放在a后,则b的起始地址是5,不是sizeof(int)的整数倍,所以
需要在a后面补充3个空字节,使得b的起始地址为8. 当放完b后,总空间为5+3+4 = 12. 接着放c,此时为 12 + 2 = 14.
2)为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,
所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。
这是说A中占用最大空间的类型,就是int型了,占用了4个字节,那么规定A占用的空间必须是4的整数倍。本来计算出来占用的空间为14,
不是4的整数倍,因此需要在最后补充2个字节。最终导致A占用的空间为16个字节。
再举个例子:
struct B
{
char *d;
short int e;
long long f;
char c[1];
}b;
void test2() {
printf("%d\n", sizeof(b));
}
对于此题,需要注意的一点是:windows系统对long long是按照8字节进行对齐的,但是Linux系统对long long则是按照4字节对齐的。
因此:
d占用4字节(因为d是指针)
e占用2字节
f占用8字节,但是其起始地址为为6,不是4的整数倍(对于Linux系统),或不是8的整数倍(对于Windows系统),因此对e之后进行字节补齐,在这里不管对于Linux还是Windows都是补充2个字节,因此 f 的起始地址是8,占用8个字节。
对于c,它占用了1个字节,起始地址是16,也是1的整数倍。
最后,在c之后需要对整个B结构体占用的空间进行补齐,目前占用空间是16+1 = 17个字节。
对于Linux,按4字节补齐(long long 是按4字节补齐的),因此补充了3位空字节,最后占用空间是 17 + 3 = 20字节。
对于Windows系统,是按8字节补齐的,因此就补充了7个字节,最后占用的空间是24字节。
参考资料
什么是static?
static 是C++中很常用的修饰符,它被用来控制变量的存储方式和可见性。
为什么要引入static?
函数内部定义的变量,在程序执行到它的定义处时,编译器为它在栈上分配空间,大家知道,函数在栈上分配的空间在此函数执行结束时会释放掉,这样就产生了一个问题: 如果想将函数中此变量的值保存至下一次调用时,如何实现? 最容易想到的方法是定义一个全局的变量,但定义为一个全局变量有许多缺点,最明显的缺点是破坏了此变量的访问范围(使得在此函数中定义的变量,不仅仅受此函数控制)。
static的作用
第一个作用是限定作用域(隐藏);第二个作用是保持变量内容持久化;
举个例子
#include<iostream>
using namespace std;
int main(){
for(int i=0; i<10; ++i){
int a = 0;
static int b = 0;
cout<<"a: "<< a++ <<endl;
cout<<"b(static): " << b++ <<endl;
}
return 0;
}
输出结果:
a: 0
b(static): 0
a: 0
b(static): 1
a: 0
b(static): 2
a: 0
b(static): 3
a: 0
b(static): 4
a: 0
b(static): 5
a: 0
b(static): 6
a: 0
b(static): 7
a: 0
b(static): 8
a: 0
b(static): 9
在模块内的static全局变量可以被模块内所有函数访问,但不能被模块外其他函数访问
在模型内的static函数只可被这一模块内的其他函数调用,这个函数的使用范围被限制在声明它的模块内。
在类中的static成员变量属于整个类所有,对类的所有对象只有一份复制。即类的所有对象访问的static成员变量是同一个,而不是对象专属的。
在类中的static成员函数属于整个类所有,这个函数不接收this指针,因而只能访问类的static成员变量。同类的static成员变量性质一样,类的对象访问的static成员函数是同一个,不是对象专属的。
参考
参考资料
防止内存泄漏
结构体:把不同类型的数据组合成一个整体-------自定义数据类型,结构体变量所占内存长度是各成员占的内存长度的总和。
联合体:使几个不同类型的变量共占一段内存(相互覆盖),共同体变量所占内存长度是各最长的成员占的内存长度。
Structure 与 Union主要有以下区别:
1.struct和union都是由多个不同的数据类型成员组成, 但在任何同一时刻, union中只存放了一个被选中的成员, 而struct的所有成员都存在。在struct中,各成员都占有自己的内存空间,它们是同时存在的。一个struct变量的总长度等于所有成员长度之和。在Union中,所有成员不能同时占用它的内存空间,它们不能同时存在。Union变量的长度等于最长的成员的长度。
2.对于union的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于struct的不同成员赋值是互不影响的。
3.联合体的各个成员共用内存,并应该同时只能有一个成员得到这块内存的使用权(即对内存的读写),而结构体各个成员各自拥有内存,各自使用互不干涉。所以,某种意义上来说,联合体比结构体节约内存。
举个例子:
typedef struct
{
int i;
int j;
}A;
typedef union
{
int i;
double j;
}U;
sizeof(A)的值是8,sizeof(U)的值也是8(不是12)。
为什么sizeof(U)不是12呢?因为union中各成员共用内存,i和j的内存是同一块。而且整体内存大小以最大内存的成员的划分。即U的内存大小是double的大小,为8了。
sizeof(A)大小为8,因为struct中i和j各自得到了一块内存,每人4个字节,加起来就是8了。
了解了联合体共用内存的概念,也就是明白了为何每次只能对其一个成员赋值了,因为如果对另一个赋值,会覆盖了上一个成员的值。
举个例子:
例如:书包;可以放置书本、笔盒、记事本等物。
联合体,仅能放入一样东西的包(限制),其尺寸,是可放物品中,最大一件的体积。
结构体,是能放入所有物品的包,所以其尺寸,可同时容纳多样物品。
联合体,同时间只能有一个成员在内。或是说,可以用不同型态,去看同一组数据。
结构体,可以包含多个成员在一起,成员都能个别操作。
TODO
TODO
static和const区别?
const和define的区别?
struct和class的区别?
sizeof和strlen的区别?
32位,64位系统中,各种常用内置数据类型占用的字节数?
virtual, inline, decltype,volatile,static, const关键字的作用?使用场景?
C++中函数指针的作用?由那些属性唯一决定一个函数指针?
C++中如何唯一确定一个重载函数?重载函数默认初始化方式?
C++多态的实现机制?虚函数表的内部实现机制?
C++中重载,覆盖,隐藏的区别?
深拷贝与浅拷贝的区别?
派生类中构造函数,析构函数调用顺序?
C++类中数据成员初始化顺序?
结构体内存对齐问题?结构体/类大小的计算?
static_cast, dynamic_cast, const_cast, reinpreter_cast的区别?
shared_ptr, unique_ptr, weak_ptr的区别?auto_ptr与shared_ptr的区别?weak_ptr主要是为了解决什么问题的?shared_ptr的内部实现?
new/delete和malloc/free的区别?
strcat,strcpy,strncpy,memset,memcpy的内部实现?
new operator, operator new, placement new的区别?
单例模式?懒汉式?饿汉式?
C++中有哪些容器(序列容器,关联容器)?vetor与list的区别?set与unordered_set的区别?
Python的全局锁
答:使用的是key-value匹配的哈希结构