字节对齐问题和 小端格式
(1) 基本数据类型的对齐
每个类型的起始地址必须是自身大小的整数倍:
char(1字节) → 任意地址。
short(2字节) → 地址是2的倍数(如0x1002, 0x1004)。
int(4字节) → 地址是4的倍数(如0x1004, 0x1008)。
double(8字节) → 地址是8的倍数(如0x1008, 0x1010)。
指针(64位系统):占8字节,对齐到8的倍数。
(2) 结构体成员的对齐
规则:每个成员起始地址满足以下较小值:
成员自身大小;
编译器默认对齐系数(通常为4或8)。
查看如下程序的输出结果
#include <stdio.h> typedef struct { unsigned int iap; unsigned char cap; unsigned short sap; unsigned char tmp; } DeviceAddr; int main(int argc, char *argv) { DeviceAddr devaddr; unsigned char *p = "d9ea327e8392xy"; printf("sizeof(devaddr)=%lu\n", sizeof(devaddr)); devaddr.tmp = 0x78; sscanf(p, "%04x%02x%06x", &devaddr.sap, &devaddr.cap, &devaddr.iap); // sscanf(p, "%04hx%02hhx%06x", &devaddr.sap, &devaddr.cap, &devaddr.iap); printf("iap: 0x%x, cap: 0x%x, sap: 0x%x, tmp=0x%x\n", devaddr.iap, devaddr.cap, devaddr.sap, devaddr.tmp); return 0; }
编译后执行结果如下:
$ ./a.out
sizeof(devaddr)=12
iap: 0x7e8392, cap: 0x32, sap: 0x0, tmp=0x0
问题:sap的结果应该是0xd9ea 才对,为什么是0 呢? 并且 tmp的值也变成 0 了?
分析:
1. 首先明确 devaddr 中各变量的内存分布,加入起始地址是0,则各变量的地址
iap :0-3
cap : 4
sap :6-7
tmp : 8
注:地址5 和 地址9-11 都是补齐用的位置
2. 使用sscanf, 将4个字符输入到 sap,即0xd9ea, 但是因为 参数是%x,这对应的是unsigned int类型,
所以会将 0x0000d9ea 存入到 sap中,但sap只有两个字节的空间,并且是 小端格式。所以
内存地址6-9的位置分别存放的是 0xea 0xd9 0x00 0x00, 此时tmp的数值 会被覆盖。
3. 然后设置cap时候,%x 接收的是0x00000032, 从而将 内存4-7的位置赋值为 0x32 0x00 0x00 0x00, 此时将sap的数值也覆盖了
4. 设置iap时,0x007e8392 分别对 内存0-3的位置赋值为 0x92 0x83 0x7e 0x00, 没有影响cap
改正方法:sscanf(p, "%04hx%02hhx%06x", &devaddr.sap, &devaddr.cap, &devaddr.iap);
sizeof(devaddr)=12
iap: 0x7e8392, cap: 0x32, sap: 0xd9ea, tmp=0x78

浙公网安备 33010602011771号