共用体和结构体字节对齐

编译器会为结构体变量中的每个数据成员分配不同的地址空间,也就是说,结构体变量中的数据程序是并列关系,而编译器为共用体变量中的数据成员分配的是同一块内存,每个时刻只有一个数据成员有意义,从地址的角度来看两者的差异,形象地表明了这一点

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//初始化方式和结构体类似
union data{   //类似于结构体变量,共享内存,共用体的大小等于最长的那一段,共用体变量在任何时刻只有一个成员变量存在,定义的时候不能初始化,只有在创建的时候才能初始化
    int price;
    char brand[20];
}d1, d2, *pData, data[10];

union key{    //共用体会存在字节数填充,直到可以被最小类型字节数整除,double有8个字节,a数组有9个,再填充7个字节,恰好被double整除
    //内存对齐的方式,分别CPU寻址
    double d;
    char a[9];
} k;   //sizeof(k) =16
void main(){
    printf("%d\n", sizeof(d1)); //20
    d1.price = 100;
    strcpy(d1.brand,"IBM");
    d2 =d1;   //共用体变量可以直接赋值
    printf("%d,%s\n",d1.price,d1.brand);  //5063241,IBM  只正确显示,最后一个赋值的变量,其他的数据解析为错误数据,因为他们共用一段内存

    union data uniondata = {100 }; //大括号初始化时,只能初始化第一个成员变量!!!共用同一片空间

    //共用体变量的三种引用方式和结构体变量类似
}

 

//初始化方式和结构体类似
union data{   //类似于结构体变量,共享内存,共用体的大小等于最长的那一段,共用体变量在任何时刻只有一个成员变量存在,定义的时候不能初始化,只有在创建的时候才能初始化
    int price;
    char brand[20];
}d1, d2, *pData, data[10];

union key{    //共用体会存在字节数填充,直到可以被最小类型字节数整除,double有8个字节,a数组有9个,再填充7个字节,恰好被double整除
    //内存对齐的方式,分别CPU寻址
    double d;
    char a[9];
} k;   //sizeof(k) =16
void main(){
    printf("%d\n", sizeof(d1)); //20
    d1.price = 100;
    strcpy(d1.brand,"IBM");
    d2 =d1;   //共用体变量可以直接赋值
    printf("%d,%s\n",d1.price,d1.brand);  //5063241,IBM  只正确显示,最后一个赋值的变量,其他的数据解析为错误数据,因为他们共用一段内存

    union data uniondata = {100 }; //大括号初始化时,只能初始化第一个成员变量!!!共用同一片空间

    //共用体变量的三种引用方式和结构体变量类似

 

结构体变量占据的内存单元的个数应当大于等于其内部所有数据成员占据内存单元数的和

出于效率的考虑,C语言引入了字节对齐机制,一般来说,不同的编译器字节对齐机制有所不同,但还是有以下3条通用准则:
(1)结构体变量的大小能够被其最宽基本类型成员的大小所整除;
(2)结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
(3)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
字节对齐第3条准则提及最宽基本类型的概念,所谓基本类型是指像char、short、int、float、double这样的内置数据类型。“数据宽度”就是指其sizeof的大小。诸如结构体、共用体和数组等都不是基本数据类型

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//第一步:找出最宽的基本数据类型
//第二步:每个成员变量都可以被最宽基本类型整除
//第三步:累加
struct data1{
    char c;        //  4   char必须能被最宽基本类型整除,所以也是4个字节
    int price;     //  4  int是最宽基本数据类型 4个字节
    char brand[19];//  20   数组是不是基本数据类型,基本数据是char类型,也要能被4整除  所以填充1个字节,就是20
}d1;  //sizeof(d1)=28

struct data2{
    char c;        //  1   char必须能被最宽基本类型整除,所以也是1个字节
    char price;     //  1  char 是最宽基本数据类型 1个字节
    char brand[19];//  19   数组是不是基本数据类型,基本数据是char类型,也要能被1整除  无需填充
}d2;  //sizeof(d2)=21

struct data3{
    char c;        //  8   char必须能被最宽基本类型8整除,所以也是8个字节
    double price;     //  8  char 是最宽基本数据类型8个字节
    char brand[19];//  24   数组是不是基本数据类型,基本数据是char类型,也要能被8整除,  填充5个字节,24个字节
}d3;  //sizeof(d3)=40
void main(){
    printf("%d\n", sizeof(d3));

    printf("%x\n",&d1);
    printf("%x\n",&d1.c);
    printf("%x\n",&d1.price);
    printf("%x\n",&d1.brand);
 /*
  * 406400   &d1
  * 406400  &d1.c             +4
    406404  &d1.price         + 4
    406408  &d1.brand           +20
    */

}

 

posted @ 2019-08-12 09:35  Coding_Changes_LIfe  阅读(1104)  评论(0编辑  收藏  举报