C语言进阶⑮(自定义类型)(结构体+枚举+联合体)(结构体实现位段)(中):https://developer.aliyun.com/article/1513097
4.3联合体大小的计算
#include <stdio.h> union Un { char a[5]; // 5个元素,一共5个字节 int i; // 4 把int 改成char下面输出就是5(和上面共用) }; int main() { union Un u; printf("%d\n", sizeof(u));//8 return 0; }
为什么又是8个字节了?
其实联合体也是存在对齐的,我们来更加系统地、详细的探究下联合体的大小规则:
联合体大小的计算:
① 联合的大小至少是最大成员的大小。
② 当最大成员的大小不是最大对齐数的整数倍时,对要对齐到最大对齐数的整数倍。
union Un { char a[5]; // 对齐数是1 int i; // 对齐数是4 }; // 所以最后取了8个字节为该联合体的大小
4.4实际运用演示(大小端)
大小端复习:C语言进阶⑩(数据的存储)(知识点+练习+作业)_GR C的博客-CSDN博客
之前学的方法:
#include <stdio.h> int check_sys() { int a = 1; return *(char*)&a;//返回1是小端,返回0是大端 } int main() { int ret = check_sys(); if (ret == 1) { printf("小端\n"); } else { printf("大端\n"); } return 0; }
通过联合体的方式判断: (通过深刻理解联合体特点写出来的代码)
#include <stdio.h> int check_sys() { union U { char c; int i; } u; u.i = 1; return u.c;//此时c和i共用字节,而c在i的第一个字节上 // 返回1 就是小端 // 返回0 就是大端 } int main() { int ret = check_sys(); if (ret == 1) { printf("小端\n"); } else { printf("大端\n"); } return 0; }
5.笔试题
5.1第一题
在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是( )
struct A { int a; short b; int c; char d; }; struct B { int a; short b; char c; int d; };
解析:
struct A { int a; //4 short b; //2 int c; //4 char d; //1 4+2+2(浪费)+4+4+1+3(浪费)=16 }; struct B { int a; //4 short b;//2 char c;//1 int d;//4 4+2+2(浪费)+1+3(浪费)+4=12 };
5.2第二题
下面代码的结果是:( )
#include<stdio.h> #pragma pack(4)/*编译选项,表示4字节对齐 平台:VS2013。语言:C语言*/ int main() { struct tagTest1 { short a; char d; long b; long c; }; struct tagTest2 { long b; short c; char d; long a; }; struct tagTest3 { short c; long b; char d; long a; }; struct tagTest1 stT1; struct tagTest2 stT2; struct tagTest3 stT3; printf("%d %d %d", sizeof(stT1), sizeof(stT2), sizeof(stT3)); return 0; } #pragma pack()
解析:
#pragma pack(4)/*编译选项,表示4字节对齐 平台:VS2013。语言:C语言*/ int main(int argc, char* argv[]) { struct tagTest1 { short a; // 2 char d; // 1 long b; //4 long c; //4 2+1+1(浪费)+4+4=12 }; struct tagTest2 { long b; //4 short c; //2 char d; //1 long a; //4 4+2+1+1(浪费)+4=12 }; struct tagTest3 { short c; //2 long b; //4 char d; //1 long a; //4 2+2(浪费)+4+1+3(浪费)+4=16 }; struct tagTest1 stT1; struct tagTest2 stT2; struct tagTest3 stT3; printf("%d %d %d", sizeof(stT1), sizeof(stT2), sizeof(stT3)); return 0; } #pragma pack()
5.3第三题
在VS2013下,这个结构体所占的空间大小是( )字节
typedef struct { int a; char b; short c; short d; }AA_t;
解析:
#include<stdio.h> typedef struct { int a; //4 char b; //1 short c; //2 short d; //2 4+1+1(浪费)+2+2+2(浪费)=12 }AA_t; int main() { printf("%d\n", sizeof(AA_t));//12 return 0; }
5.4第四题
下面代码的结果是:( )
#include <stdio.h> union Un { short s[7]; int n; }; int main() { printf("%d\n", sizeof(union Un)); return 0; }
解析:
#include <stdio.h> union Un { short s[7]; //2*7=14 int n; //4 }; int main() { printf("%d\n", sizeof(union Un));//16 共用,且默认对齐数是4 return 0; }
5.5第五题
在X86下,有下列程序输出结果是( )
#include<stdio.h> int main() { union { short k; char i[2]; }*s, a; s = &a; s->i[0] = 0x39; s->i[1] = 0x38; printf("%x\n", a.k); return 0; }
解析:
#include<stdio.h> int main() { union { short k;//2 char i[2];//2 //低地址 高地址 }*s, a; //i[0] i[1] s = &a; //一个空间 一个空间 s->i[0] = 0x39; //0x39 一个空间 s->i[1] = 0x38; //0x39 0x38 printf("%x\n", a.k); //3839 (小端存储)(地位放在低地址,高位放在高地址) return 0; }
5.6第六题
下面代码的结果是( )
#include<stdio.h> enum ENUM_A { X1, Y1, Z1 = 255, A1, B1, }; int main() { enum ENUM_A enumA = Y1; enum ENUM_A enumB = B1; printf("%d %d\n", enumA, enumB); return 0; }
解析:
#include<stdio.h> enum ENUM_A { X1, //0 Y1, //1 Z1 = 255, //255 A1, //256 B1, //257 }; int main() { enum ENUM_A enumA = Y1; enum ENUM_A enumB = B1; printf("%d %d\n", enumA, enumB);// 1 257 return 0; }
5.7第七题
下面代码的结果是( )
#include<stdio.h> #include<string.h> int main() { unsigned char puc[4]; struct tagPIM { unsigned char ucPim1; unsigned char ucData0 : 1; unsigned char ucData1 : 2; unsigned char ucData2 : 3; }*pstPimData; pstPimData = (struct tagPIM*)puc; memset(puc, 0, 4); pstPimData->ucPim1 = 2; pstPimData->ucData0 = 3; pstPimData->ucData1 = 4; pstPimData->ucData2 = 5; printf("%02x %02x %02x %02x\n", puc[0], puc[1], puc[2], puc[3]); return 0; }
A.02 03 04 05
B.02 29 00 00
C.02 25 00 00
D.02 29 04 00
解析:
puc是一个char数组,每次跳转一个字节,结构体不是,它只有第一个元素单独享用一字节,
其他三个元素6个比特位一起共用一字节,所以puc被结构体填充后,本身只有两个字节会被写入,
后两个字节肯定是0,至此AD排除,然后第一个字节给2就是2了,第二个字节比较麻烦,
首先ucData0给了3其实是越界了,1位的数字只能是0或1,所以11截断后只有1,
同理ucData1给的4也是越界的,100截断后是00,只有5的101是正常的。
填充序列是类似小端的低地址在低位,所以排列顺序是00 101 00 1。也就是0010 1001,即0x29,
故选B
5.8第八题
有如下宏定义和结构定义当A=2, B=3时,pointer分配( )个字节的空间。
(其实是算结构体类型大小*2+3)
#define MAX_SIZE A+B struct _Record_Struct { unsigned char Env_Alarm_ID : 4; unsigned char Para1 : 2; unsigned char state; unsigned char avail : 1; }*Env_Alarm_Record; struct _Record_Struct* pointer = (struct _Record_Struct*)malloc (sizeof(struct _Record_Struct) * MAX_SIZE);
解析:
结构体向最长的char对齐,前两个位段元素一共4+2比特位,不足8比特位,合起来占1字节,
第三个元素占一个字节,最后一个元素一个比特位单独1字节,一共3字节。
另外,#define执行的是查找替换, sizeof(struct _Record_Struct) * MAX_SIZE这个语句
其实是3*2+3,结果为9
本篇完。