惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 靖意风

使用QT 将可执行程序 进行打包 对使用的屏幕的整理 对mmc 设备进行分区 开发板启动时间优化 nmcli 设置网络配置 虚拟机下 安装 ubuntu 18.04 硬件基础知识__串口 在ubuntu下 编译23位的测试文件 31_了解 x6818开发板是 如何使用/dev/ttySAC0 进行打印log 10_linux dirver platform 框架 ubuntu24.04.02 下安装软件 记录 ubuntu 更新源 vmware 虚拟机的三种网卡 vmware 安装 ubuntu 24.04.02 07_linux 字符设备了解 04_kernel编程框架和 printk传参 05_使用linux内核的gpio库函数 03_uboot 命令整理 01_stm32 裸板程序 01_了解嵌入式开发
字节对齐问题和 小端格式
靖意风 · 2025-07-16 · via 博客园 - 靖意风

(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