Q:关于结构体的对齐,到底遵循什么原则?
A:首先先不讨论结构体按多少字节对齐,先看看只以1字节对齐的情况:

#include <stdio.h>
#include <string.h>

#define PRINT_D(intValue)     printf(#intValue" is %d\n", (intValue));
#define OFFSET(struct,member)  ((char *)&((struct *)0)->member - (char *)0)

#pragma pack(1)

typedef struct
{
    char    sex;
    short   score;
    int     age;
}student;

int main()
{
    PRINT_D(sizeof(student))
    PRINT_D(OFFSET(student,sex))
    PRINT_D(OFFSET(student,score))
    PRINT_D(OFFSET(student,age))
    ;
}

输出:
sizeof(student) is 7
OFFSET(student,sex) is 0
OFFSET(student,score) is 1
OFFSET(student,age) is 3
可以看到,如果按1字节对齐,那么结构体内部的成员紧密排列,sizeof(char) == 1, sizeof(short) == 2, sizeof(int) == 4.

修改上面的代码, 去掉#pragma pack语句,代码如下:

#include <stdio.h>
#include <string.h>

#define PRINT_D(intValue)     printf(#intValue" is %d\n", (intValue));
#define OFFSET(struct,member)  ((char *)&((struct *)0)->member - (char *)0)

typedef struct
{
    char    sex;
    short   score;
    int     age;
}student;

int main()
{
    PRINT_D(sizeof(student))
    PRINT_D(OFFSET(student,sex))
    PRINT_D(OFFSET(student,score))
    PRINT_D(OFFSET(student,age))
    ;
}

运行结果:
sizeof(student) is 8
OFFSET(student,sex) is 0
OFFSET(student,score) is 2
OFFSET(student,age) is 4

此时,各个成员之间就不像之前那样紧密排列了,而是有一些缝隙。这里需要介绍下对齐原则:

此原则是在没有#pragma pack语句作用时的原则(不同平台可能会有不同):

原则A:struct或者union的成员,第一个成员在偏移0的位置,之后的每个成员的起始位置必须是当前成员大小的整数倍;

原则B:如果结构体A含有结构体成员B,那么B的起始位置必须是B中最大元素大小整数倍地址;

原则C:结构体的总大小,必须是内部最大成员的整数倍;

依据上面3个原则,我们来具体分析下: sex在偏移0处,占1字节;score是short类型,占2字节,score必须以2的整数倍为起始位置,所以它的起始位置为2; age为int类型,大小为4字节,它必须以4的整数倍为起始位置,因为前面有sex占1字节,填充的1字节和score占2字节,地址4已经是4的整数倍,所以age的位置为4.最后,总大小为4的倍数,不用继续填充。

继续修改上面的代码,增加#pragma pack语句:

#include <stdio.h>
#include <string.h>

#define PRINT_D(intValue)     printf(#intValue" is %d\n", (intValue));
#define OFFSET(struct, member)  ((char *)&((struct *)0)->member - (char *)0)

#pragma pack(4)

typedef struct
{
    char    sex;
    short   score;
    int     age;
}student;

int main()
{
    PRINT_D(sizeof(student))
    PRINT_D(OFFSET(student,sex))
    PRINT_D(OFFSET(student,score))
    PRINT_D(OFFSET(student,age))
    ;
}

运行结果:
sizeof(student) is 8
OFFSET(student,sex) is 0
OFFSET(student,score) is 2
OFFSET(student,age) is 4

具体分析下:

有了#pragma pack(4)语句后,之前说的原则A和C就不适用了。实际对齐原则是自身对齐值(成员sizeof大小)和指定对齐值(#pragma pack指定的对齐大小)的较小者。依次原则,sex依然偏移为0, 自身对齐值为1,指定对齐值为4,所以实际对齐为1; score成员自身对齐值为2,指定对齐值为4,实际对齐为2;所以前面的sex后面将填充一个1字节,然后是score的位置,它的偏移为2;age自身对齐值为4,指定对齐为4,所以实际对齐值为4;前面的sex和score正好占用4字节,所以age接着存放;它的偏移为4.

Q:关于位域的问题,空域到底表示什么?
A:它表示之后的位域从新空间开始。

#include <stdio.h>
#include <string.h>

#define PRINT_D(intValue)     printf(#intValue" is %d\n", (intValue));
#define OFFSET(struct, member)  ((char *)&((struct *)0)->member - (char *)0)

typedef struct
{
    ;
    ;
    ;
    ;
}bit_info;

int main()
{
    PRINT_D(sizeof(bit_info))
    ;
}

运行结果:
sizeof(bit_info) is 8
bit_info中的a, b占用4个字节的前4位,到int:0; 时表示此时将填充余下所有没有填充的位,即刚刚的4个字节的余下28位;int d:2; 将从第四个字节开始填充,又会占用4个字节,所以总大小为8.

C语言结构体的对齐原则的更多相关文章

  1. C语言 结构体(联合体)对齐规则

    /* 结构体(联合体)对齐规则 */ #include <stdio.h> #include <stdlib.h> #include <string.h> /* * ...

  2. [置顶] 什么是C语言结构体字节对齐,为什么要对齐?

    一.概念 对齐跟数据在内存中的位置有关.如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐.比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的.   ...

  3. C语言 结构体字节对齐问题

    摘选自这位大神的博客 方法一: 结构体在内存中分配一块连续的内存,但结构体内的变量并不一定是连续存放的,这涉及到内存对齐. 原则1  数据成员对齐规则:结构(struct或联合union)的数据成员, ...

  4. C语言 结构体中的成员域偏移量

    //C语言中结构体中的成员域偏移量 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> # ...

  5. C语言结构体的字节对齐原则

    为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据 ...

  6. 解析C语言结构体对齐(内存对齐问题)

    C语言结构体对齐也是老生常谈的话题了.基本上是面试题的必考题.内容虽然很基础,但一不小心就会弄错.写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的 ...

  7. C语言结构体对齐

    1.结构体变量中的元素如何访问? (1)数组中元素的访问方式:表面上有2种方式(数组下标方式和指针方式):实质上都是指针方式访问.(2)结构体变量中的元素访问方式:只有一种,用.或者->的方式来 ...

  8. C语言 结构体的内存对齐问题与位域

    http://blog.csdn.net/xing_hao/article/details/6678048 一.内存对齐 许多计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地 ...

  9. C语言结构体变量字节对齐问题总结

    结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但 ...

随机推荐

  1. oracle分组查询

    分组函数 在分组函数中,如果有一个查找项分组,其他项必须也分组,比如下面的语句会报错,因为sal分组了,而ename没有分组: 1.显示工资最高的员工: 2.显示所有员工的平均工资: 2.1使用系统函 ...

  2. Java基础知识强化之集合框架笔记57:Map集合之HashMap集合(HashMap<Student,String>)的案例

    1. HashMap集合(HashMap<Student,String>)的案例 HashMap<Student,String>键:Student      要求:如果两个对象 ...

  3. iOS UIKit:CollectionView之布局(2)

    Collection view使用UICollectionViewFlowLayout对象来管理section中的cell,该对象是一种流布局方式,即在collection view中的section ...

  4. Ubuntu安装sar出错Please check if data collecting is enabled in /etc/default/sysstat

    1.安装sysstat apt-get install sysstat 2.安装后无法使用: Cannot open /var/log/sysstat/sa02: No such file or di ...

  5. log4j的properties详细配置,分级输出日志文件

            log4j是很常用的日志类包,在此做一下配置的记录 加载jar包和properities配置文件             将commons-logging.jar和logging-lo ...

  6. ubuntu下创建c语言程序之hello world

    将要学习c语言了,先记录一下在ubuntu下,使用vim创建一个最基本的hello world程序: 打开终端,使用cd命令转到操作的目录,如我在home下的program files文件内创建, 就 ...

  7. 【转】关于C#接口和抽象类的一些说明

    接口和抽象类 1.概念 什么是接口? 接口是包含一组虚方法的抽象类型,其中每一种方法都有其名称.参数和返回值. 接口方法不能包含任何实现,CLR允许接口可以包含事件.属性.索引器. 一个类可以实现多个 ...

  8. C语言基础知识小总结(1)

    这几天在学习C语言,零零散散的学了十来天,这两天由于家里来了朋友,也没有顾得上写个总结,今天刚把朋友送走,下面就把这十来天的学习情况总结一下,一边在以后好复习与查看. 一.流程控制包括:顺序语句.判断 ...

  9. struts -执行流程

    When a client request is given, a web container will receive request Web container loads web.xml and ...

  10. pat_1008

    1008. 数组元素循环右移问题 (20) 时间限制 400 ms 内存限制 32000 kB 代码长度限制 8000 B 判题程序 Standard 一个数组A中存有N(N>0)个整数,在不允 ...