仔细讨论 C/C++ 字节对齐问题⭐⭐
原文:https://www.cnblogs.com/AlexMiller/p/5509609.html
字节对齐的原因
为了提高 CPU 的存储速度,编译器会对 struct 和 union的存储进行优化,即进行字节对齐。
对齐方式
对于 struct 或 union 中的 struct 或者 union 来说,它们的字节对齐标准就是它的所有成员中字节数最大的数据的字节数。
一般情况下 C/C++ 的变量所占用的字节数
char: 1字节;
short: 2字节;
int: 4字节;
long: 4字节;
long long: 8字节;
float: 4字节;
double: 8字节;
bool: 1字节;
*struct 中字节对齐需要满足的条件:对齐两原则
1、某个变量存放的起始位置相对于结构的起始位置的偏移量是该变量字节数的整数倍;
2、结构所占用的总字节数是结构种字节数最长的变量的字节数的整数倍。
例:

1 struct Struct
2 {
3 double d1;
4 char d2;
5 int d3;
6 }a;

sizeof(a) = 8 + 1 + 3 + 4 = 。其中补上的 3 个字节是为了让 int 型数据的起始位置相对于结构起始位置的偏移量为 4 的整数倍。

1 struct Struct
2 {
3 char d1;
4 double d2;
5 int d3;
6 }b;

sizeof(b) = 1 + 7 + 8 + 4 = 。 20 / 8 = 2 …… 4,所以需要再补上 4 个字节,使之成为 8 的 整数倍
*union 中字节对齐需要满足的两个条件:对齐两原则
1、unoin 的大小必须足够容纳最宽的成员;
2、union 的大小需要能够被其所包含的基础成员类型的大小所整除。
字节对齐的另一种方式
VC提供了 #pragma pack(n) 用来自定义字节对齐方式
有一下两种情况:
1、n 大于变量的字节数:偏移量只满足默认的字节对齐方式;
2、n 小于变量所占的字节数:偏移量是 n 的整数倍,不使用默认的字节对齐方式。
例:
#pragma pack(push) // 保持对齐状态
#pragma pack(4) // 设定为 4 字节对齐
struct test
{
char m1;
double m2;
int m3;
}a;
#pragma pack(pop) // 恢复对齐状态
sizeof(a) = + + + = // 其中补上三位是因为 n 小于 8,所以 m2 的起始位置相对于结构起始位置的偏移量是 n,即为 4. #pragma pack(8)
struct S1
{
char a;
long b;
};
struct S2
{
char c;
struct S1 d;
long long e;
};
#pragma pack() sizeof(S1) = + + =
sizeof(S2) = + + + + = 。// 其中加上的 4 是因为变量 e 的字节数是 8 ,其相对与起始位置的偏移量必须是 8 的倍数。???
字节对齐问题的讨论到上边已经结束了。下面再加上我碰到的两道题目作为实例:
1、典 ⭐⭐⭐
#include <stdio.h>
union
{
char x[];
int i;
}a; int main()
{
a.x[] = ;
a.x[] = ;
printf("%d\n", a.i);
printf("%d\n", sizeof(a));
return ;
}
输出为 266 8
解析:
对 union 分配内存涉及字节对齐问题,在上方已有详细描述,在此只简单解释一番。union 分配的内存必须是 union 中所有基本数据类型的倍数。
在此题中即为 1 和 4 的倍数,又 char x[5] 占用 5 个字节,故 union 分配的内存大小应为 8 个字节。
windows 系统中高字节在后,低字节在前。而 char x[5] 只有前两个元素有值,即两个值只占 2 个字节,也即 union 中的 int 型数据中只有低两位上有值。
即 i 的二进制表示为:
00000000 00000000 00000001 00001010
即: 2^1 + 2^3 + 2^8 = 266
也相当于十六进制 0x010A, 即: 10 * 16^0 + 1 * 16^2 = 266
题2
struct T {
char a;
int *d;
int b;
int c:;
double e;
};
T *p;
正确答案: C 你的答案: C (正确)
A:sizeof(p) == 24 (8)
B:sizeof(*p) == 24 (32)
C:sizeof(p->a) == 1
D:sizeof(p->e) == 4 (8)
a占一个字节(注:地址为[0]),d作为64位指针占8个字节(注1:32位占四个字节,p也一样)(注2:根据上面的准则2,d的偏移量要为8的整数倍,所以d的地址为[8]-[15],而非[1]-[8],下同),b占了4个字节(注:地址为[16][19]),c指定为16为,占了两个字节(注:地址为[20,21]),e占8个字节,(同d的分析一样,e的地址应该为[24][31]),所以A的答案应该是8,B的答案是32,C正确,D的答案为8。
这里补充一下进制转换问题,也是我一并搜集来的:
进制互相转换
| 十进制 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 十六进制 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
| 二进制 | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 |
十六进制数字转换十进制数字:
0x2AF5转换十进制:
5 * 16^0 = 5
F * 16^1 = 240
A * 16^2 = 2560
2 * 16^3 = 8192
---------------
5 + 240 + 2560 + 8192 = 10997
十进制数字转换十六进制数字:
2500转换十六进制:
2500 / 16 = 156 …… 4
156 / 16 = 9 …… 12(C)
9 / 16 = 0 …… 9
----------------------
得到4C9,倒转9C4,即2500的十六进制表示是: 0x9C4
二进制数字转换十六进制数字:
101110011011.1001
采取四合一法,即以二进制的小数点为分界点,向左(或向右)每四位取一位。
组分好以后,对照二进制与十六进制数的对应表,将四位二进制按权相加,得到的数就是一位十六进制数,然后按顺序排列,小数点的位置不变。
结果为:B9B.9
需要注意的是,在向左(或向右)取四位时,取到最高位(最低位)如果无法凑足四位,就可以在小数点的最左边(或最右边)补0,进行换算。
十六进制数字转换二进制数字:
对照二进制与十六进制数的对应表,将十六进制数分为二进制数字,用四位二进制数字按权相加,最后得到二进制数字,小数点依旧。
2、

1 #include <iostream>
2 using namespace std;
3
4 typedef struct A
5 {
6 char aChar;
7 int aInt_2;
8 short aInt;
9 }TypeA;
10
11 typedef struct B
12 {
13 char bChar[3];
14 TypeA bA;
15 double bDouble;
16 }TypeB;
17
18 int main()
19 {
20 TypeA a;
21 TypeB b;
22 cout << sizeof(a) << endl << sizeof(b) << endl;
23 return 0;
24 }

输出为 12 24
解析:
由上述对字节对齐问题的讨论很容易便可以得出此题的答案。
sizeof(TypeA) = 1 + 3 + 4 + 2 = 10。 10 / 4 = 2 …… 2,故需要再补上 2 个字节,即 sizeof(TypeA) = 12;
sizeof(TypeB) = 3 + 1 + 12 + 8 = 24。之所以补上 1 个字节是因为 TypeA 类型在 struct TypeB 中的默认对齐方式
是 4 个字节(即 int 的字节大小,也即 struct TypeA 中最长的字节)。
仔细讨论 C/C++ 字节对齐问题⭐⭐的更多相关文章
- C语言结构体的字节对齐原则
为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据 ...
- C语言:内存字节对齐详解[转载]
一.什么是对齐,以及为什么要对齐: 1. 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问, ...
- ARM字节对齐问题详解
一.什么是字节对齐,为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这 ...
- C ~ C语言字节对齐
1. 什么是对齐? 现代计算机中内存空间都是按照字节(byte)划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型 ...
- C语言字节对齐
转自:http://blog.csdn.net/21aspnet/article/details/6729724 文章最后本人做了一幅图,一看就明白了,这个问题网上讲的不少,但是都没有把问题说透. 一 ...
- C语言字节对齐 __align(),__attribute((aligned (n))),#pragma pack(n)
转载地址 : http://blog.csdn.net/21aspnet/article/details/6729724 一.概念 对齐跟数据在内存中的位置有关.如果一个变量的内存地址正好位于它 ...
- c语言,内存字节对齐
引用:内存字节对齐 写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的变量总长度要大,这是怎么回事呢?讲讲字节对齐吧. /************* ...
- stm32中字节对齐问题(__align(n),__packed用法)
ARM下的对齐处理 from DUI0067D_ADS1_2_CompLib 3.13 type qulifiers 有部分摘自ARM编译器文档对齐部分 对齐的使用: 1.__align(n ...
- 【C语言】字节对齐问题(以32位系统为例)
1. 什么是对齐? 现代计算机中内存空间都是按照字节(byte)划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型 ...
随机推荐
- Struts 入门(一) 搭建Struts环境
eclipse中创建项目 搭建步骤: 1.创建web项目 2.下载导入相关jar包 3.创建并完善相关配置文件 4.创建(控制器)Action 并测试启动 1.文件--新建--动态web项目 给项目起 ...
- 云计算之路-阿里云上:对“黑色n秒”问题的最终猜想——CPU C-states引起的
如果说2013年云计算之路的主题是“踩坑”,那么2014年我们希望云计算之路的主题变成“填坑”——当然填坑是阿里云来完成的,我们只是见证曾经的坑坑洼洼变成平坦大道. 15号(周四)晚上我们发现了SLB ...
- 跟着包子学 css (一)
1.在每次 写css之前 都应该先将浏览器的默认 样式 给清除掉 *{padding:0; margin:0;} h1,h2,h3,h4,h5,h6{font-weight:normal; font- ...
- 让IIS8支持WCF的最简单方法
以前在IIS8中使用WCF时,总是参考在IIS8添加WCF服务支持这篇博文进行手工设置: 1. 首先添加MIME类型:扩展名“.svc”,MIME类型 “application/octet-strea ...
- Spoken English Practice(Don't get me wrong, that explanation makes no difference, I'm still mad at you. Come on, be reasonable!)
绿色:连读: 红色:略读: 蓝色:浊化: 橙色:弱读 下划线_为浊化 口语蜕变(2017/7/11) ...
- 2017 Multi-University Training Contest - Team 1—HDU6040
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6040 题意:不知道北航的同学为何解释题意之前都要想一段故事,导致刚开始题意不是很懂,题意就是给你n,m ...
- BSSID,SSID,ESSID区别
SSID(Service Set Identifier) SSID,AP唯一的ID码,许多人认为可以将SSID写成ESSID,其实不然,SSID是个笼统的概念,包含了ESSID和BSSID,用来区 ...
- tomcat启动报错:Injection of autowired dependencies failed
Error creating bean with name 'backPrintPaperController': Injection of autowired dependencies failed ...
- Python并行编程(六):线程同步之条件
1.基本概念 条件指的是应用程序状态的改变.其中某些线程在等待某一条件发生,其 他线程会在该条件发生的时候进行通知,一旦条件发生,线程会拿到共享资源的唯一权限. 2.示例代码 from threadi ...
- 前端之masonry(图片瀑布流插件)
加载代码: 1 2 <script src="http://libs.baidu.com/jquery/1.8.3/jquery.min.js"></script ...