结构体

  • 结构体有名定义
  • 无名定义
  • 结构体嵌套定义
  • 结构体内存对齐
  • 结构体成员初始化
  • 结构体变量引用
  1. 结构体的有名定义:直白点就是在struct 之后跟着结构体的名称,如下:
struct str_test{
    int a;
    char b;
};
  1. 结构体的无名定义:注意与有名定义的区别。这种方式不提倡,但是系统支持
struct {
    int c;
    char e;
}var1,var2;  //结构体定义完毕直接定义变量。
  1. 结构体的嵌套定义:
struct str_test3{
    int length;
    int wide;
    int high;
    struct str_test4{
      int id;
      struct str_test3 var;
  };
};//这种也可以,但是不提倡使用。

struct str_test3{
    int length;
    int wide;
    int high;
};
struct str_test4{
    int id;
    struct str_test3 var;
};//是最常用方式,结构体互相独立;
  1. 结构体内存对齐
    1)、平台原因:不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
    2)、性能原因:数据结构应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

这些问题既和软件相关又和硬件相关。

  1. 所谓软件相关主要是指和具体的编程语言的编译器的特性相关,编译器为了优化CPU访问内存的效率,在生成结构体成员的起始地址时遵循着某种特定的规则,这就是所谓的 结构体成员“对齐”;
  2. 所谓硬件相关主要是指CPU的“字节序”问题,也就是大于一个字节类型的数据如int类型、short类型等,在内存中的存放顺序,即单个字节与高低地址的对应关系。

字节序分为两类:Big-Endian和Little-Endian,有的文章上称之为“大端”和“小端”,他们是这样定义的:
Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端;
Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

最本质原因是基本数据类型的长度有大有小,在使用的时候不可能长短一样,但CPU为了提高效率需要大批量一次访问多个内存区,可能存在同一个数据由于没有字节对齐而出现跨字节访问,这样效率会下降,甚至有些CPU会异常,比如一个大小固定的盒子如果要放进去不整齐的筷子,就会很麻烦要么折断要么换盒子,最好就是将筷子对齐同时放入盒子。

其中筷子也有大头和小头之分,具体怎么放那是一个约定,只要整体系统都采用统一的大头或小头就行。

我们在做盒子放筷子的试验的时候,很多时候是我们人工可识别的,能很智能完成复杂操作,那么计算机在处理数据的过程中的字节是怎么对齐的呢?

首先我们的程序在编译阶段,编译器会稍微做些智能化的工作,将内存的分配过程中按照一定的规则对齐,GCC 默认的对齐字节是 4字节, vc 默认的对齐字节是 8字节。

在编译过程中有个开关可以控制对齐的字节大小: #pragma pack(n) 这个宏就是来控制编译过程中的字节对齐用的,其中的 n 就是你可定制的对齐字节大小,如果不设置就按默认值处理。

我们可以编写程序来验证字节对齐的神奇:

struct A
{
    char a;
    int c;
};

问 如上结构体的大小是多少?为什么? 这是一个企业面试题,类似的面试题多不胜数。

将这个结构体编写程序跑起来看看就知道了,在运行之前我们按照以前学习的基本知识计算出 结果应该是:char =1 int =4 所以结果应该是5
但是非常抱歉,程序的运行结果却是:8 ,到底是我们计算错误还是计算机出故障了?其实我们都没错,计算机也没错 ,就是字节对齐的起作用。
编译器在编译代码的过程中,根据如下原则对数据对齐

  1. 数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。
  2. 结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。)
    原则
  3. 收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。
  4. 结构体中的字节对齐,如果成员的大小大于等于4字节,则以4字节对齐,然后再排列下一个成员。如果两个成员的大小加起来大于四字节,则这两个相邻成员仍分别按照四字节对齐。仅当两个相邻成员的总大小在四字节内的时候,才会一起按照四字节对齐。
    Demo:
typedef struct {
    char a;
    int b;
    short c;
}Demo1;
Demo1 tmp;
sizeof(Demo1)=12
("%p", &tmp.a) = 0
("%p", &tmp.b) = 4
("%p", &tmp.c) = 8
Demo1 tmp.png
typedef struct {
    char a;
    short b;
    int c;
}Demo2;
Demo2 tmp;
sizeof(Demo2)=8
("%p", &tmp.a) = 0
("%p", &tmp.b) = 2
("%p", &tmp.c) = 4
Demo2 tmp.png
typedef struct {
    char a;
    char b[4];
    short c; //int c
}Demo3;
Demo3 tmp;
sizeof(Demo3)=8 // 12
("%p", &tmp.a) = 0
("%p", &tmp.b) = 1
("%p", &tmp.c) = 6
Demo3 short.png
Demo3 int.png

所以我们在使用结构体的过程中一定要注意它的这个特性,尤其是在需要用到结构体大小的地方,一定要考虑字节对齐产生的影响。

1)联合体是一个结构;
2)它的所有成员相对于基地址的偏移量都为0;
3)此结构空间要大到足够容纳最"宽"的成员;
4)其对齐方式要适合其中所有的成员;

  1. 结构体成员初始化
struct str_test
{
    int a;
    int b;
};
struct str_test var = {10,20};   ///结构体定义与变量定义分离,变量的初始化一次性完成
struct str_test var2 = {.a=30};  ///结构体变量的成员可以单独指定

等价

struct str_test var2 ;
    var2.a =30;
struct str_test2
{
    int aa;
    int bb;
    struct str_test cc;
};
struct str_test2 var3 = {10,20,{30,40}};   ///嵌套结构体初始化一次性完成 
struct str_test2 var5 = {.cc.a =10};       ///嵌套结构体成员变量的逐层赋值
struct str_test3
{
    int a;
    int b;
}var6,var7;  ///定义结构体的时候定义变量
struct str_test4
{
    int a;
    int b;
}var8 = {100,200};  ///定义结构体的时候定义变量并初始化
  1. 结构体变量的引用:
    1、变量名.成员 ;
    2、指针变量 ->成员;
struct str_test var;
   var.a =10;
   var.b =20;
struct str_test pvar = NULL;    ///结构体指针与基本数据类型的指针一样,必须指向一个实际的内存地址。    
pvar = (strcut str_test *) malloc(sizeof(struct str_test));

或者 定义变量同时定义指针:
struct str_test var, *pvar; pvar = &var;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容