目录
大小端
一、什么是大小端模式
一个32位的2进制在内存中存储时有两种发布方式:
高字节 对应 高地址 --------------> 小端模式
高字节 对应 低地址 --------------> 大端模式
示意图如下:
二、为什么会有大小端之分
1. 一开始是由于不同架构的CPU处理多个字节数据的顺序不一样,比如x86的是小段模式,KEIL C51是大端模式。但是后来互联网流行,TCP/IP协议规定为大端模式,为了跨平台通信,还专门出了网络字节序和主机字节序之间的转换接口(ntohs、htons、ntohl、htonl)
2. 大小端模式各有优势:小端模式强制转换类型时不需要调整字节内容,直接截取低字节即可;大端模式由于符号位为第一个字节,很方便判断正负。
三、怎样判断大小端
基本思想室根据数据截断来判断是大端还是小端
1、通过强制类型转换截断
BOOL IsBigEndian()
{
short a = 0x1234;
char b = *(char*)&a;
if(0x12 == b)
{
return TRUE;
}
return FALSE;
}
2、利用联合体共享内存的特性,截取低地址部分
BOOL IsBigEndian()
{
union NUM
{
short a;
char b;
}num;
num.a = 0x1234;
if(0x12 == num.b)
{
return TRUE;
}
return FALSE;
}
字节对齐
1、什么是内存对齐?
理论上计算机对于任何变量的访问都可以从任意位置开始,然而实际上系统会对这些变量的存放地址有限制,通常将变量首地址设为某个数N的倍数,这就是内存对齐。
2、为什么要内存对齐?
- 硬件平台限制,内存以字节为单位,不同硬件平台不一定支持任何内存地址的存取,一般可能以双字节、4字节等为单位存取内存,为了保证处理器正确存取数据,需要进行内存对齐。
- 提高CPU内存访问速度,一般处理器的内存存取粒度都是N的整数倍,假如访问N大小的数据,没有进行内存对齐,有可能就需要两次访问才可以读取出数据,而进行内存对齐可以一次性把数据全部读取出来,提高效率。
3、内存对齐规则?
- 数据成员对齐规则:struct或者union的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员都按照#pragma pack数值和这个数据成员自身大小中更小的那个进行对齐。
- 整体对齐规则:struct或者union的首地址按照内部最大数据成员的大小和#pragma pack数值较小的那个N进行对齐,并且结构体的总大小为N的整数倍,如有必要编译器也会在最后一个成员后面填充一些字节用于对齐。
4、C++如何进行内存对齐?
class A
{
int a;
char d;
};
// 创建给定类型对象大小满足对齐要求的未初始化内存块,在一个内存对齐的缓冲区上创建对象
// C++11后可以这样操作
void align_cpp11_after()
{
static std::aligned_storage<sizeof(A),
alignof(A)>::type data;
A *attr = new (&data) A;
}
// C++11之前
void align_cpp11_before()
{
static char data[sizeof(void *) + sizeof(A)];
const uintptr_t kAlign = sizeof(void *) - 1;
char *align_ptr =
reinterpret_cast<char *>(reinterpret_cast<uintptr_t>(data + kAlign) & ~kAlign);
A *attr = new (align_ptr) A;
}
ADC读取左对齐与右对齐
1.右对齐数据读取问题
其转换结果可以读取的语句为: resualt=int(ADCH)*256+ADCL;
右对齐的时候,10位ADC的结果表示方式为ADCH:ADCL,ADCH是10bit结果的高2位,ADCL是10bit结果的低8位,如果要将ADC的结果存储到一个int型的变量中,那就需要先将ADCH的结果左移8位,再和ADCL的相加,其原理如下图所示:左移8位等价于乘以256. 也可以将ADC转化为以256为权的数值表示,即:
resualt = int(ADCH)*256^1+ADCL*256^0; 这样就可以清楚地理解这个数字的含义了。
2.左对齐数据读取问题
同理,左对齐如下表示: