C/C++字节对齐规则

1、对齐规则
字节对齐与具体编译器相关,但一般都遵循以下三条规则:
(1)结构、联合或类的数据成员,第一个相对于首地址放在偏移为0的地方;
(2)结构、联合或类的各成员相对于首地址的偏移量,都是#pragma pack指定的数值和该成员大小中较小那个的整数倍。如有需要编译器会在成员之间加上填充字节;
(3)结构、联合或类的总大小为最宽基本类型成员大小与#pragma pack指定的数值中较小那个的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。

很多GCC编译器默认的#pragma pack值为8字节。

typedef struct{
    short a; //规则(1),并根据规则(2)填充,占用空间[0~7]
    double b; //规则(2),占用空间[8~15]
    int c; //规则(3),默认8字节对齐,占用空间[16~23]
}sB;
输出:sizeof(sB) = 24

//#pragma pack(4)
typedef struct{
    short a; //规则(1),根据规则(2)填充,占用空间[0~3]
    double b; //规则(2),占用空间[4~11]
    int c; //规则(3),占用空间[12~15]
}sB4;
//#pragma pack()
输出:sizeof(sB4) = 16;

2、C++无数据成员类
无数据成员的类(包括空类),编译器分配1个字节的内存空间。这样的意义在于,创建的实例所指向的就是有意义的内存空间。

如果基类无数据成员,C++标准允许派生类的第一个成员与基类共享地址,基类并没有占据任何实际的空间。但若派生类的第一个成员类型仍然是基类,编译器仍会为基类分配1字节的空间,这是因为C++标准要求类型相同的对象必须地址不同。

#include <iostream>
using namespace std;
 
class A1{};
class A2{};
 
class B1:public A1{
public:
    A1 a1;   //分配1字节空间
    char ca;   //分配1字节空间
};//由于基类放在开始,因此还要给基类分配1字节空间。总共1+1+1=3字节
 
class B2:public A1{
public:
    A2 a2;  //A2非基类。给a2分配1字节空间
    char ca; //分配1字节空间
};//总共1+1=2字节
 
class B3:public A1{
public:
    char ca; //分配1字节空间,与基类A1共享1字节
    A1 a1; //给a1分配1字节空间
};
 
int main() {
    cout<<sizeof(B1)<<endl;
    cout<<sizeof(B2)<<endl;
    cout<<sizeof(B3)<<endl;
    return 0;
}

输出:
3
2
2

3、关于基本数据类型和指针大小
(1)int类型以及指针类型所占字节的大小由什么决定的?
首先,介绍几个基本概念:(主要摘自百度百科)
  机器字长:在同一时间中处理二进制数的位数叫字长。通常称处理字长为8位数据的CPU叫8位CPU,32位CPU就是在同一时间内处理字长为32位的二进制数据。字长由微处理器(CPU)对外数据通路的数据总线条数决定。
  寻址空间:寻址空间一般指的是CPU对于内存寻址的能力。CPU最大能查找多大范围的地址叫做寻址能力 ,CPU的寻址能力以字节为单位 (字节是最小可寻址单位),如32位寻址的CPU可以寻址2的32次方大小的地址也就是4G,这也是为什么32位寻址的CPU最大能搭配4G内存的原因 ,再多的话CPU就找不到了。
  
  这里CPU的寻址位数是由地址总线的位数决定,32位CPU的寻址位数不一定是32位,因为32位CPU中32的意义为字长。

​有关寻址范围计算解释,对于32位寻址的CPU,其地址值为32位的二进制数,所以可以表示的最大地址为2的32次方(即4G,最大内存空间为4GB,这里G表示数量、GB表示容量)。同时我们不难看出,一个指针的值就是一个32位的二进制数,32位对应 4字节(Byte)。所以,指针的大小实际上是由CPU的寻址位数决定,而不是字长

(2)int类型的长度??
准确的字节数依赖于机器字长和编译器

现阶段32bit(即4字节)PC一般在绝大多数编译器下是32bit,当然也有的编译器是16bit(比如turbo C)。最关键一点,只能小,不能大,这是因为即使编译器把它当作大于32bit了,但因为CPU字长只有32bit,所以也只能处理32bit的数。

同时需要注意的就是 在c标准中只是对不同的数据类型的数字范围设置了下界,但是没有上界。

(3)指针的类型是由什么决定的呢?
指针的大小是由内存寻址空间决定的,即地址总线决定。
一般32位机寻址空间4G,所以指针占4字节;
一般8位的单片机寻址空间是64k,所以指针占2字节。

(4)针对跨平台 int类型数据大小不一致而采取的措施
​ uint8_t,uint16_t,uint32_t等都不是什么新的数据类型,它们只是使typedef给类型起的别名。不过,不要小看了typedef,它对于你代码的维护会有很好的作用。比如C中没有bool,于是在一个软件中,一些程序员使用int,一些程序员使用short,会比较混乱,最好就是用一个typedef来定义,如:
typedef char bool;

一般来说,一个C的工程中一定要做一些这方面的工作,因为你会涉及到跨平台,不同的平台会有不同的字长,所以利用预编译和typedef可以让你最有效的维护你的代码,在我们知道编译器的int类型数据大小时,直接在typedef 更改就行,不需要一个一个的更改。测试当前编译器int数据类型大小的方法为sizeof(int);

为了用户的方便,C99标准的C语言硬件为我们定义了这些类型,我们放心使用就可以了。

按照posix标准,一般整形对应的*_t类型为:
1字节 uint8_t
2字节 uint16_t
4字节 uint32_t
8字节 uint64_t

#ifndef __INTTYPES_H_  
#define __INTTYPES_H_  
/* Use [u]intN_t if you need exactly N bits. 
   XXX- doesn't handle the -mint8 option.  */  
typedefsigned char int8_t;  
typedefunsigned char uint8_t;  
typedefint int16_t;  
typedefunsigned int uint16_t;  
typedeflong int32_t;  
typedefunsigned long uint32_t;  
typedeflong long int64_t;  
typedefunsigned long long uint64_t;  
typedefint16_t intptr_t;  
typedefuint16_t uintptr_t;  
#endif

参考:
https://blog.csdn.net/qq_30263737/article/details/81177763
https://blog.csdn.net/gogomusic/article/details/80286343

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值