C语言字节对齐问题(以32位系统为例)

  1. 什么是对齐?

  现代计算机中内存空间都是按照字节(byte)划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序地一个接一个地排放,这就是对齐。

  2. 计算机为什么要对齐?

  各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取,其他平台可能没有这种情况。但是最常见的是,如果不按照适合其平台的要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,一个int型(假设为 32位)如果存放在偶地址开始的地方,那么一个读周期就可以读出,而如果存放在奇地址开始的地方,就可能会需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该int数据,显然在读取效率上下降很多。这也是空间和时间的博弈。在网络程序中,掌握这个概念可是很重要的:如果在不同平台之间(比如在Windows 和Linux之间)传递2进制流(比如结构体),那么在这两个平台间必须要定义相同的对齐方式,不然莫名其妙地出了一些错,可是很难排查的。

  3. 一个对齐的例子

  通常,我们写程序的时候,不需要考虑对齐问题,编译器会替我们选择适合目标平台的对齐策略。当然,我们也可以通知给编译器传递预编译指令而改变对指定数据的对齐方法,比如写入预编译指令#pragma pack(2),即告诉编译器按两字节对齐。

  但是,正因为我们一般不需要关心这个问题,所以,如果编辑器对数据存放做了对齐,而我们不了解的话,常常会对一些问题感到迷惑。最常见的就是struct数据结构的sizeof结果,比如以下程序:

#include <stdio.h>

void main(){

    struct A{
        char a;
        short b;
        int c;
    };

    printf( "size of struct A = %d \n", sizeof(struct A) );

}

  输出结果为:8字节。

  如果我们将结构体中的变量声明位置稍加改动(并不改变变量本身),请再看以下程序:

#include <stdio.h>

void main(){

    struct A{
        short b;
        int c;
        char a;
    };

    printf( "size of struct A = %d \n", sizeof(struct A) );

}

  输出结果为:12字节。

  问题出来了,他们都是同一个结构体,为什么占用的内存大小不同呢?为此,我们需要对对齐算法有所了解。

  4. 对齐算法

  由于各个平台和编译器的不同,现以32位,vc++6.0系统为例,来讨论编译器对struct数据结构中的各成员如何进行对齐的。

  首先,我们给出四个概念:

  1)数据类型自身的对齐值:就是基本数据类型的自身对齐值,比如char类型的自身对齐值为1字节,int类型的自身对齐值为4字节。

  2)指定对齐值:预编译命令#pragma pack (value)指定的对齐值value。

  3)结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值,比如以上的struct A的对齐值为4。

  4)数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中较小的那个值。

  设结构体如下定义:

struct A{
    char a;
    short b;
    int c;
};

  a是char型数据,占用1字节内存;short型数据,占用2字节内存;int型数据,占用4字节内存。因此,结构体A的自身对齐值为4。于是,a和b要组成4个字节,以便与c的4个字节对齐。而a只有1个字节,a与b之间便空了一个字节。我们知道,结构体类型数据是按顺序存储结构一个接一个向后排列的,于是其存储方式为:

  其中空白方格无数据,是浪费的内存空间,共占用8字节内存。

  实际上,为了更加明显地表示“对齐”,我们可以将以上结构想象为以下的行排列:

  对于另一个结构体定义:

struct A{
        short b;
        int c;
        char a;
    };

  其内存存储方式为:

  同样把它想象成行排列:

  可见,浪费的空间更多。

  其实,除了结构体之外,整个程序在给每个变量进行内存分配时都会遵循对齐机制,也都会产生内存空间的浪费。但我们要知道,这种浪费是值得的,因为它换来的是效率的提高。

  以上分析都是建立在程序默认的对齐值基础之上的,我们可以通过添加预定义命令#pragma pack(value)来对对齐值进行自定义,比如#pragma pack(1),对齐值变为1,此时内存紧凑,不会出现内存浪费,但效率降低了。效率之所以降低,是因为:如果存在更大字节数的变量时(比1大),比如int类型,需要进行多次读周期才能将一个int数据拼凑起来。

  参考资料:

  [1] http://blog.sina.com.cn/s/blog_715de2f50100pgs3.html

  [2] http://baike.baidu.com/view/1523557.htm?fr=aladdin

时间: 2024-10-13 04:00:49

C语言字节对齐问题(以32位系统为例)的相关文章

C语言字节对齐问题详解【转】

引言 转自:http://www.cnblogs.com/clover-toeic/p/3853132.html 考虑下面的结构体定义: 1 typedef struct{ 2 char c1; 3 short s; 4 char c2; 5 int i; 6 }T_FOO; 假设这个结构体的成员在内存中是紧凑排列的,且c1的起始地址是0,则s的地址就是1,c2的地址是3,i的地址是4. 现在,我们编写一个简单的程序: 1 int main(void){ 2 T_FOO a; 3 printf(

分享一篇文章C语言字节对齐问题(适用于C++)转载至http://blog.csdn.net/21aspnet/article/details/6729724

文章最后本人做了一幅图,一看就明白了,这个问题网上讲的不少,但是都没有把问题说透. 一.概念    对齐跟数据在内存中的位置有关.如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐.比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的.   二.为什么要字节对齐   需要字节对齐的根本原因在于CPU访问数据的效率问题.假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x000000

C语言字节对齐 __align(),__attribute((aligned (n))),#pragma pack(n)

转载地址 : http://blog.csdn.net/21aspnet/article/details/6729724 一.概念    对齐跟数据在内存中的位置有关.如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐.比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的.   二.为什么要字节对齐   需要字节对齐的根本原因在于CPU访问数据的效率问题.假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访

64位系统与32位系统区别

64 位的优点:64 位的应用程序可以直接访问 4EB 的内存和文件大小最大达到4 EB(2 的 63 次幂):可以访问大型数据库.本文介绍的是64位下C语言开发程序注意事项. 1. 32 位和 64 位C数据类型 32和64位C语言内置数据类型,如下表所示: 上表中第一行的大写字母和数字含义如下所示:I表示:int类型L表示:long类型P表示:pointer指针类型32表示:32位系统64表示64位系统如:LP64表示,在64位系统下的long类型和pointer类型长度为64位.64位Li

为什么32位系统最大支持4G内存??我自己悟出来了 终于 。。。。。

今天突然开窍了,想通了..... 以下是我的抽象想法: 32位系统 这个 多少位 指的是 硬件的 一次性发送过来的位数,一个字节 等于8位,内存的一个存储单元就是一个字节,即8位. 也可以这样来想这个位,就是栈中内存地址的二进制 位数,那么 32位 的意思是 栈中内存地址最大是 32个11,即: 你会发现,32位系统的 最大内存地址为:2的32次方 - 1,最小地址地址为:0-----因为计算机都是从0开始的.32个0 也是 一个内存地址. 那么32位系统的 最大寻址空间是:0 — (2的32次

Visual Studio2015 (VS2015)简体中文版 安装教程(在Win 8.1 32位系统中)

VS2015简体中文版安装 导航 介绍 解决安装先决条件 安装 VS2015 创建桌面快捷方式 启动 VS2015 命令启动VS2015 配置 VS2015 启动完成 MSDN安装 启动MSDN Visual Studio的功能添加和删除 Visual Studio的卸载 补一张安装完成的 介绍    返回顶部 由于安装在不同的操作系统中会遇到不同错误的提示 所以,不会在本篇文章中介绍 Visual Studio2015 在不同操作系统的安装方法. 如果在安装过程中遇到了问题 请在百度中搜索相关

详解为什么32位系统只能用4G内存.

本文转自:https://www.cnblogs.com/nvd11/archive/2013/04/02/2996784.html,感谢作者的干货 既然是详解, 就从最基础的讲起了. 1. Bit(位)              Bit计算机是计算机最小的存储单位,  大家都知道计算机实质上都是用二进制数0或者1来存储数据的,  所以Bit实际上可以看成存放1个二进制数字的1个位置.             也就是说bit只有2种值, 0 或者 1, 所以1个bit能存放1个布尔类型的值(bo

百杂讲堂之为什么32位系统只能操作4g内存

百杂讲堂之为什么32位系统只能操作4g内存 计算机内存中很多的单元,每一个单元就是一个字节,一个字节有8位.每一个单元有两种状态:0和1. 所以 两个单元就有4个组合: 3个单元就有8个组合: 依次类推--: n个地址就有2的n次方组合. 32位计算机,就有32个的单元,就能控制2^32个单元,即2^32个字节,也就是2^32B,等于4GB,所以32位系统的计算机只能控制4gb的内存. 很多人也就想到了,现在有64位的系统,那么也就有2^64个单元,约等于17,179,869,184GB,oh

【Android】cocos2d-x-3.1.1环境搭建与创建工程( Win7 32位系统)

参考资料: http://blog.csdn.net/wxc237786026/article/details/32907079 1.环境搭建 2.创建工程 2.1 VS2012运行 2.2 Android实体机运行 1.环境搭建 安装工具: 1.1.JDK 1.2.Android SDK 1.3.Android NDK 1.4.apache-ant 1.5.Python 1.6   coco2d-x-3.1.1 1.1.JDK安装与配置 参考:http://jingyan.baidu.com/