C语言进阶⑮(自定义类型)(结构体+枚举+联合体)(结构体实现位段)(下)

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: C语言进阶⑮(自定义类型)(结构体+枚举+联合体)(结构体实现位段)

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


本篇完。


003574b302194ffcb426a418edc83366.jpg

目录
打赏
0
0
0
0
47
分享
相关文章
|
1月前
|
【C语言程序设计——循环程序设计】枚举法换硬币(头歌实践教学平台习题)【合集】
本文档介绍了编程任务的详细内容,旨在运用枚举法求解硬币等额 - 循环控制语句(`for`、`while`)及跳转语句(`break`、`continue`)的使用。 - 循环嵌套语句的基本概念和应用,如双重`for`循环、`while`嵌套等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台将对编写的代码进行测试,并给出预期输出结果。 5. **通关代码**:提供完整的代码示例,帮助理解并完成任务。 6. **测试结果**:展示代码运行后的实际输出,验证正确性。 文档结构清晰,逐步引导读者掌握循环结构与嵌套的应用,最终实现硬币兑换的程序设计。
52 19
|
1月前
|
【C语言程序设计——枚举】得到 3 种不同颜色的球的可能取法(头歌实践教学平台习题)【合集】
本关任务要求从红、黄、蓝、白、黑五种颜色的球中,每次取出3个不同颜色的球,列举所有可能的排列情况。通过定义枚举类型和使用嵌套循环语句实现。枚举类型用于表示球的颜色,循环语句用于生成并输出所有符合条件的排列 编程要求:在指定区域内补充代码,确保输出格式正确且完整。测试说明:平台将验证代码输出是否与预期一致,包括每种排列的具体顺序和总数。 示例输出: ``` Output: 1 red yellow blue 2 red yellow white ... 60 black white blue total: 60 ```
51 4
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
199 14
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
结构体通过`struct`关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
213 10
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
63 23
|
1月前
|
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
70 15
|
1月前
|
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
61 24
|
1月前
|
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
68 16
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
37 3

热门文章

最新文章