云计算百科
云计算领域专业知识百科平台

自定义类型:结构体

目录

一、结构体类型的基础

(一)什么是结构体

1、结构体的本质

2、结构体与数组的对比

(二)结构体类型的声明与定义

1、声明与定义的区别

2、结构体的定义

3、定义 “书” 的结构体类型

(三)结构体变量的创建与初始化

1、结构体变量的创建

2、结构体变量的初始化

(四)结构体成员的访问与打印

1、直接访问:变量名.成员名

2、指针访问:指针名->成员名

(五)结构体的特殊声明——匿名结构体

1、 定义与特性

2、类型独立性

3、使用限制

(六)结构体的自引用

1、错误与正确实现对比

2、自引用中的重命名问题

二、结构体内存对齐

(一)内存对齐现象

(二)内存对齐规则

规则 1:第一个成员的对齐

规则 2:其他成员的对齐

规则 3:结构体总大小的对齐

规则 4:嵌套结构体的对齐

(三)对齐规则实例计算

案例 1:基础结构体(struct S1)

案例 2:包含 double 的结构体(struct S3)

案例 3:嵌套结构体(struct S4)

(四)内存对齐的原因

1、平台原因(兼容性)

2、性能原因(效率)

(五) 内存对齐的优化与调整

1、成员顺序优化

2、修改默认对齐数

三、结构体传参

(一)传参方式对比

1、传值调用

2、传址调用

(二)常见错误与解决

1、错误案例:类型未定义

(三)传址调用的优势与安全性

四、结构体实现位段

(一)位段的定义与语法

1、成员类型限制

2、比特位指定

(二)位段的空间优势

(三)位段的内存分配规则 (★)

(四)位段的跨平台问题

1、符号性不确定

2、最大位数不确定

3、存储顺序不确定

4、剩余空间处理不确定

(五)位段的应用

(六)位段的使用注意事项

1、禁止取地址操作

2、取值范围限制


一、结构体类型的基础

(一)什么是结构体
1、结构体的本质

        一种 “自定义复合类型”,用于封装多个不同类型的成员变量

        我们可以与数据类比,数组也是一些值的结合,不过数组里面存储的一个或多个成员,它们的类型是相同的,属于同类型元素。

        我们常用结构体去描述复杂实体,如 “书” 包含书名、作者、定价,“学生” 包含学号、姓名、成绩。

2、结构体与数组的对比
特征数组结构体
元素 / 成员类型 必须相同 可以不同
存储方式 连续内存空间,无对齐 连续内存空间,需对齐
访问方式 下标索引(如a[0]) 成员名(如b.book_name)
声明语法 类型 数组名[大小]; struct 标签 {成员};
(二)结构体类型的声明与定义
1、声明与定义的区别

(1)声明:只是 “告知” 编译器存在某个结构体类型,不涉及内存分配,也不算 “创建” 出可直接使用的类型实体。

// 结构体声明(不完整类型)
struct Student; // 仅声明存在 struct Student 类型

(2)定义:才是真正 “创建” 出完整的结构体类型 —— 编译器会根据定义确定其内存布局和大小,此时才能用它来创建变量(分配内存)。

2、结构体的定义

struct 结构体标签名 {     成员类型1 成员名1;  // 成员1     成员类型2 成员名2;  // 成员2     // … 更多成员(成员列表) } (全局)变量列表;  // 可选:声明类型时直接创建全局变量

3、定义 “书” 的结构体类型

// 声明结构体类型(struct Book为类型名,不可省略struct)
struct Book {
char book_name[20]; // 书名(字符串,20个字符)
char author[20]; // 作者(字符串,20个字符)
float price; // 定价(浮点数)
char id[10]; // 书号(字符串,10个字符)
} b4, b5, b6; // 全局变量:b4、b5、b6(程序运行期间一直存在)

int main() {
// 局部变量:b1、b2、b3(仅在main函数中有效)
struct Book b1, b2, b3;
return 0;
}

(三)结构体变量的创建与初始化
1、结构体变量的创建

(1)在定义的时候直接创建全局变量【如上面 b4,b5,b6 所示】

(2)定义完结构体类型后,再创建局部变量【如上面 b1, b2 ,b3 所示】

Tip:可以创建完局部变量后直接初始化,不一定要分步。

2、结构体变量的初始化

(1)按成员顺序初始化(推荐)

        规则:初始化值的顺序必须与结构体成员声明顺序一致,未初始化成员默认为 0(或空字符串)。

struct Book b1 = {"中国文脉", "余秋雨", 38.8f, "20251002"};

(2)指定成员初始化(灵活)

        规则:通过.(成员名)指定初始化的成员,顺序可任意,未指定成员默认为 0。

struct Book b2 = {.id="20251003", .book_name="吾家小史", .author="余秋雨", .price=26.6f};

(四)结构体成员的访问与打印
1、直接访问:变量名.成员名

(1)适用场景:直接操作结构体变量(非指针)。

(2)示例:打印 b1 和 b2 的成员

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

struct Book {
char book_name[20];
char author[20];
float price;
char id[10];
};

int main() {
struct Book b1 = { "中国文脉", "余秋雨", 38.8f, "20251002" };
struct Book b2 = { .id = "20251003", .book_name = "吾家小史", .author = "余秋雨", .price = 26.6f };

// 打印b1
printf("书名:%s\\n", b1.book_name);
printf("作者:%s\\n", b1.author);
printf("定价:%.2f\\n", b1.price); // %.2f:保留2位小数,减少误差显示
printf("书号:%s\\n\\n", b1.id);

// 打印b2
printf("书名:%s\\n", b2.book_name);
printf("作者:%s\\n", b2.author);
printf("定价:%.2f\\n", b2.price);
printf("书号:%s\\n", b2.id);

return 0;
}

2、指针访问:指针名->成员名

(1)适用场景:通过指针操作结构体变量。

(2)示例:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

struct Book {
char book_name[20];
char author[20];
float price;
char id[10];
};

int main() {
struct Book b1 = { "中国文脉", "余秋雨", 38.8f, "20251002" };
struct Book* p = &b1; // 结构体指针p指向b1

// 通过指针访问成员
printf("书名:%s\\n", p->book_name);
printf("作者:%s\\n", p->author);
return 0;
}

(五)结构体的特殊声明——匿名结构体
1、 定义与特性

        匿名结构体类型是一种不完全声明,通过省略结构体的类型名称实现。其核心特性是一次性使用,仅能在声明结构体的同时创建变量,后续无法再通过该类型创建新变量

// 匿名结构体类型声明,同时创建变量s1、s2
struct {
char c;
double d;
} s1, s2;

        上述代码中,s1 和 s2 是基于该匿名结构体类型创建的变量,之后若想再创建同类型变量,如struct s3;,编译器会报错,因为该结构体没有可复用的类型名称。

2、类型独立性

        即使两个匿名结构体的成员列表完全一致,编译器也会将它们视为完全独立的两种类型。这会导致基于不同匿名结构体类型的指针与变量无法兼容。

// 匿名结构体类型1,创建变量s1
struct {
int a;
char b;
} s1;

// 匿名结构体类型2,创建指针p
struct {
int a;
char b;
} *p;

// 错误:编译器认为s1和p的类型不同
p = &s1;

        本质原因:匿名结构体无明确类型标识,编译器无法判定两个成员相同的匿名结构体属于同一类型,因此禁止跨类型的指针赋值操作。

3、使用限制

        匿名结构体类型仅适用于单次使用场景,例如临时存储少量数据且后续无需扩展。

        实际开发中,若需多次复用结构体类型或进行指针操作,应优先使用带类型名称的常规结构体声明,避免因类型不兼容导致错误。

(六)结构体的自引用

        结构体自引用指在结构体内部包含“指向自身类型的成员”,常用于实现链表、树等数据结构。但自引用的实现方式有严格要求,错误的实现会导致编译异常。

1、错误与正确实现对比

(1)错误方式

① 代码示例:struct Node { int data; struct Node next; };

② 问题分析:直接嵌套同类型结构体变量,会导致结构体大小无限递归(next内部又包含struct Node),编译器无法计算其大小,直接报错。

(2)正确方式

① 代码示例:struct Node{ int data; struct Node* next; }; 

② 问题分析:使用指针成员next,指针仅存储地址(32 位平台占 4 字节,64 位平台占 8 字节),结构体大小可计算,通过指针链接下一个节点,符合链表节点的设计逻辑。

(3)最通俗易懂的解释

        错误代码里是 struct Node next;,也就是在这个 “盒子 (Node) ” 里,又放了一个一模一样的 “盒子 (Node) ”。那新放的这个 “盒子” 里,是不是又得再放一个一模一样的 “盒子”?

        这样下去,就会有无穷多个 “盒子” 套在一起,根本没办法确定这个 “盒子” 到底有多大,编译器自然就搞不定了。

        正确代码里是 struct Node* next;,这里的 * 表示指针,指针就像一个 “地址标签”。这个 “盒子 (Node) ” 里放的不是另一个 “盒子”,而是一张写着 “下一个盒子在哪里” 的 “地址标签 (指针) ”。

        “地址标签” 本身很小(32 位系统下占 4 字节,64 位系统下占 8 字节),所以这个 “盒子” 的大小是能确定的。当需要找下一个 “盒子” 时,就看这个 “地址标签” 上写的地址,去那个地址找下一个 “盒子” 就行,这就符合了链表 “一个接一个” 的逻辑。

2、自引用中的重命名问题

        使用 typedef 对结构体类型重命名时,需注意类型的定义顺序。若在结构体内部直接使用重命名后的类型声明指针成员,会因类型尚未完全定义而报错。

// 错误:重命名后的Node在结构体内部尚未生效
typedef struct {
int data;
Node* next; // 编译器无法识别Node类型
} Node;

// 正确:先声明结构体,再重命名
typedef struct Node {
int data;
struct Node* next; // 使用原始类型名struct Node
} Node;

        关键规则:结构体自引用时,必须使用完整的原始类型名(struct 类型名)声明指针成员,不能依赖尚未定义完成的类型别名。

        所以如果要使用结构体的自引用,就不要使用匿名结构体,因为你没有 “struct 标签名” 这种可以在内部直接书写的完整名。

二、结构体内存对齐

        结构体内存对齐是计算结构体大小的核心机制,也是笔试和面试中的高频考点。

        其本质是通过牺牲部分空间,换取硬件对内存的高效访问(用空间换时间);需掌握具体对齐规则才能准确计算结构体大小。

(一)内存对齐现象

        即使结构体成员的类型和数量完全相同,仅调整成员的声明顺序,结构体的实际大小也可能发生显著变化,这一现象由内存对齐规则导致。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
// 用于使用 offsetof 宏
#include <stddef.h>

// 结构体 S1:成员顺序为 char、char、int
struct S1 {
char c1;
char c2;
int n;
};

// 结构体 S2:成员顺序为 char、int、char
struct S2 {
char c1;
int n;
char c2;
};

int main() {
// 打印结构体 S1 和 S2 的大小
printf("sizeof(struct S1) = %zu 字节\\n", sizeof(struct S1));
printf("sizeof(struct S2) = %zu 字节\\n", sizeof(struct S2));

// 使用 offsetof 宏查看结构体 S1 成员的偏移量
printf("S1 中 c1 的偏移量:%zu\\n", offsetof(struct S1, c1));
printf("S1 中 c2 的偏移量:%zu\\n", offsetof(struct S1, c2));
printf("S1 中 n 的偏移量:%zu\\n", offsetof(struct S1, n));

// 使用 offsetof 宏查看结构体 S2 成员的偏移量
printf("S2 中 c1 的偏移量:%zu\\n", offsetof(struct S2, c1));
printf("S2 中 n 的偏移量:%zu\\n", offsetof(struct S2, n));
printf("S2 中 c2 的偏移量:%zu\\n", offsetof(struct S2, c2));

return 0;
}

        在常见的 32 位或 64 位环境(如 VS 环境)下,char 类型占 1 字节,int 类型占 4 字节。内存对齐的规则简单来说,是为了让结构体成员的地址满足一定的对齐要求,以提高内存访问效率。

        而 offsetof 是 C 标准库中的一个宏,定义在 <stddef.h> 头文件中。它的作用是计算结构体成员在结构体中的偏移量(以字节为单位)。

(二)内存对齐规则

        结构体内存对齐遵循四条核心规则,适用于所有结构体(包括嵌套结构体):

规则 1:第一个成员的对齐

        结构体的第一个成员必须对齐到结构体变量起始位置偏移量为 0 的地址处,即第一个成员始终从结构体的起始地址开始存储,无空间间隙。

规则 2:其他成员的对齐

        除第一个成员外,其他成员需对齐到「对齐数」的整数倍地址处。

对齐数计算:编译器默认对齐数与该成员自身大小的较小值。

VS 环境:默认对齐数为 8

Linux(gcc)环境:无默认对齐数,对齐数即成员自身大小

        例如,VS 环境下int类型成员的对齐数为min(8, 4) = 4。8 这是 VS 环境的默认对齐数,4这是int 类型的自身大小,所以最后两者之间选择小的那个为 4.

        因此int成员必须从偏移量为 4、8、12 等 4 的倍数地址开始存储。

规则 3:结构体总大小的对齐

        结构体的总大小必须是所有成员中 “最大对齐数” 的整数倍。若当前计算的总大小不满足该条件,需自动填充字节至最大对齐数的整数倍。

规则 4:嵌套结构体的对齐

        如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,而非外部结构体的对齐数。

        结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。

(三)对齐规则实例计算
案例 1:基础结构体(struct S1)

struct S1 {
char c1; // 1字节,对齐数1,偏移0
char c2; // 1字节,对齐数1,偏移1
int n; // 4字节,对齐数4,需从4的倍数地址开始,偏移4-7
};

            成员存储:c1(0)c2(1)n(4-7)

            总大小计算:当前占用 8 字节,最大对齐数为 4(int 的对齐数),8 是 4 的整数倍,因此总大小为 8 字节(浪费 2-3 字节)。

    案例 2:包含 double 的结构体(struct S3)

    struct S3 {
    double d; // 8字节,对齐数8,偏移0-7
    char c; // 1字节,对齐数1,偏移8
    int i; // 4字节,对齐数4,需从12开始(跳过9-11),偏移12-15
    };

            成员存储:d(0-7)、c(8)、i(12-15)

            总大小计算:当前占用 16 字节,最大对齐数为 8(double的对齐数),16 是 8 的整数倍,总大小为 16 字节(浪费 9-11 字节)。

    案例 3:嵌套结构体(struct S4)

    // 嵌套的结构体S3,内部最大对齐数为8
    struct S3 {
    double d;
    char c;
    int i;
    };

    struct S4 {
    char c1; // 1字节,对齐数1,偏移0
    struct S3 s3; // 嵌套结构体,需对齐到自身最大对齐数8,偏移8-23(16字节)
    double d; // 8字节,对齐数8,偏移24-31
    };

            成员存储:c1(0)、s3(8-23)、d(24-31)

            总大小计算:当前占用 32 字节,最大对齐数为 8(s3和d的对齐数),32 是 8 的整数倍,总大小为 32 字节(浪费 1-7 字节)。

    (四)内存对齐的原因

            内存对齐并非语法限制,而是由硬件平台特性和性能需求决定,主要包括两个核心原因:

    1、平台原因(兼容性)

            并非所有硬件平台都能访问任意地址上的任意类型数据。

            部分硬件平台(如早期嵌入式处理器)仅能在特定地址处访问特定类型数据,例如要求整型数据必须从 4 的倍数地址开始读取,否则会抛出硬件异常。内存对齐可确保数据存储符合硬件访问规则,避免程序崩溃。

    2、性能原因(效率)

            数据结构(尤其是栈)应该尽可能地在自然边界上对齐。

            原因在于,处理器访问内存时,通常以 “块” 为单位。如 32 位处理器一次读取 4 字节,64 位处理器一次读取 8 字节。若数据未对齐,可能需要两次内存访问才能获取完整数据;而对齐的数据仅需一次访问即可。

            未对齐场景:int 成员从偏移量 1 开始存储,需先读取 0-3 字节(获取该int的前 3 字节),再读取 4-7 字节(获取后 1 字节),共两次操作。

            对齐场景:int 成员从偏移量 4 开始存储,一次读取 4-7 字节即可获取完整数据,效率显著提升。

            本质:内存对齐是 “空间换时间” 的优化策略,通过少量空间浪费换取内存访问效率的提升。

    (五) 内存对齐的优化与调整
    1、成员顺序优化

            通过调整结构体成员的声明顺序,将空间较小的成员集中存放,可减少因对齐产生的空间浪费。例如:

    //优化前
    struct S1
    {
    char c1;
    int i;
    char c2;
    };

    //优化后
    struct S2
    {
    char c1;
    char c2;
    int i;
    };

            两者成员完全相同,但优化后节省 4 字节空间,原因是两个 char 成员集中存放,减少了空间碎片(减少了内存对齐导致的 “填充空间”)。

    2、修改默认对齐数

            编译器支持通过 “#pragma pack(n)” 指令修改默认对齐数(n通常为 2 的幂次方,如 1、2、4、8),使用 “#pragma pack()” 可恢复默认对齐设置。

    // 设置默认对齐数为1(取消对齐,成员紧密排列)
    #pragma pack(1)
    struct S {
    char c1;
    int n;
    char c2;
    };
    // 恢复默认对齐
    #pragma pack()

    // 此时sizeof(struct S) = 6字节(1+4+1),无空间浪费

            注意:修改默认对齐数需谨慎,仅在对内存占用要求极高(如嵌入式开发)且明确硬件支持的场景下使用,否则可能导致性能下降或兼容性问题。

    三、结构体传参

            结构体传参有两种方式:传值调用和传址调用,两者在空间占用、性能和功能上存在显著差异,实际开发中需优先选择传址调用。以下是实际案例:

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>

    struct S
    {
    int data[1000];
    int num;
    };

    // 结构体传参
    void print1(struct S s)
    {
    printf("%d\\n", s.num);
    }

    // 结构体地址传参
    void print2(struct S* ps)
    {
    printf("%d\\n", ps->num);
    }

    int main()
    {
    struct S s = { {1,2,3,4}, 100 };
    print1(s); // 传结构体
    print2(&s); // 传地址
    return 0;
    }

    (一)传参方式对比
    1、传值调用

    (1)实现原理:创建结构体参数的副本(形参),函数内操作副本

    (2)空间占用:复制整个结构体,若结构体较大(如包含 1000 元素的数组),空间浪费严重

    (3)功能限制:无法修改实参,仅能读取数据

    (4)适用场景:结构体较小且无需修改实参的场景

    2、传址调用

    (1)实现原理:传递结构体变量的地址(指针),函数内通过指针访问实参

    (2)空间占用:仅占用指针大小(4/8 字节),空间占用固定

    (3)功能限制:可修改实参,功能灵活

    (4)适用场景:结构体较大、需高效传参或修改实参的场景

            函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。

    (二)常见错误与解决
    1、错误案例:类型未定义

    // 错误:使用结构体前未定义类型
    void print1(struct S s) {
    // 打印成员…
    }

    struct S {
    int a;
    char b;
    };

    int main() {
    struct S s = {10, 'a'};
    print1(s);
    return 0;
    }

    (1)错误原因:编译器按代码顺序编译,调用 print1时 struct S 尚未定义,无法识别参数类型。

    (2)解决方法:将结构体类型定义移至函数声明之前,确保编译器编译函数时已知晓结构体类型。

    (三)传址调用的优势与安全性

            传址调用的核心优势是高效,无论结构体多大,仅需传递 4/8 字节的地址,避免了大量数据拷贝的时间和空间开销。

            若需防止函数意外修改实参,可在指针参数前添加限定符,确保实参只读:

    // const限定:函数仅能读取s指向的结构体,无法修改
    void print2(const struct S* s) {
    printf("%d %c\\n", s->a, s->b);
    }

    int main() {
    struct S s = {10, 'a'};
    print2(&s); // 传地址,高效且安全
    return 0;
    }

            结论:结构体传参优先选择传址调用,结合 const 可兼顾效率与安全性。

    四、结构体实现位段

            位段是结构体的扩展特性,通过精确控制成员占用的比特位数,实现内存的精细化管理,适用于成员取值范围有限的场景(如状态标志、协议字段)。

    (一)位段的定义与语法

            位段的声明与结构体相似,但有两个关键区别:

    1、成员类型限制

            位段成员必须是int、unsigned int或signed int(C99 后支持char等其他整型类型)。

    2、比特位指定

            成员名后需添加冒号(:)和数字,指定该成员占用的比特位数。

    // 变量前面可以有下划线,但是不能以数字开头
    // 位段类型声明:_a占2bit,_b占5bit,_c占10bit,_d占30bit
    struct A {
    int _a : 2;
    int _b : 5;
    int _c : 10;
    int _d : 30;
    };

            注意:单个成员的比特位数不能超过其类型的总比特数( 如int类型最大支持 32 比特,因此_d:30合法,_d:33非法 )。

    (二)位段的空间优势

            位段的核心价值是节省内存。当成员的取值范围有限时,无需分配完整的字节(如int占 4 字节),仅需分配足够表示取值的比特位即可

            例如:表示 0-3 的状态(共 4 种取值),仅需 2 比特(_a:2),相比int的 4 字节(32 比特),空间节省 93.75%。

            ★实测:上面的 struct A 的大小为 8 字节(2+5+10+30=47 比特,需 6 字节,但因对齐规则分配 8 字节),而若用普通结构体(4 个int),大小为 16 字节,空间节省 50%。

    (三)位段的内存分配规则 (★)

            位段的内存分配“成员类型的字节大小” 为单位,按需开辟空间,具体规则如下:

            若成员类型为int(4 字节):每次开辟 4 字节(32 比特),用完后再开辟新的 4 字节。若成员类型为char(1 字节):每次开辟 1 字节(8 比特),用完后再开辟新的 1 字节。

            以下面代码为例:

    struct B {
    char _a : 3; // 3bit
    char _b : 4; // 4bit
    char _c : 5; // 5bit
    char _d : 4; // 4bit
    };

    struct B b = {0};
    s.a = 10;
    s.b = 12;
    s.c = 3;
    s.d = 4;

              第一步:开辟 1 字节 (8 比特),存储_a(3bit) 和 _b(4bit),剩余 1 比特 (不足存储 _c 的 5bit,浪费)。

              第二步:开辟第 2 字节 (8 比特),存储_c(5bit),剩余 3 比特 (不足存储 _d 的 4bit,浪费) 。

              第三步:开辟第 3 字节(8 比特),存储_d(4bit),剩余 4 比特。

              总大小:3 字节(符合char类型的分配规则)。

      (四)位段的跨平台问题

              位段的实现依赖编译器,存在显著的跨平台兼容性问题,主要体现在以下四点:

      1、符号性不确定

              int类型的位段可能被编译器视为有符号或无符号,若最高位为 1,有符号位段会被解析为负数,无符号则为正数。

      2、最大位数不确定

              16 位平台的int为 2 字节(16 比特),32 位平台为 4 字节(32 比特),若位段成员指定 30 比特,在 16 位平台会报错。

      3、存储顺序不确定

              编译器可能从字节的高位向低位存储位段成员,也可能从低位向高位存储(如_a:3可能占用字节的 0-2 比特,也可能占用 5-7 比特)。

      4、剩余空间处理不确定

              当字节剩余空间不足存储下一个位段成员时,编译器可能浪费剩余空间并开辟新字节,也可能复用其他字节的剩余空间。

              结论:位段适用于对内存敏感且无需跨平台的场景(如嵌入式硬件寄存器映射、网络协议封装),注重可移植性的程序应避免使用。

      (五)位段的应用

              下图是网络协议中,IP数据报的格式,我们可以看到其中很多的属性只需要个 bit 位就能描述,这里使用位段,能够实现想要的效果,也节省了空间,这样网络传输的数据报大小也会较小一些,对网络的畅通是有帮助的。

      (六)位段的使用注意事项
      1、禁止取地址操作

              位段成员可能共用同一字节,而内存中仅对字节分配地址,字节内部的比特位无独立地址。因此,无法对位段成员使用取址运算符(&),也不能通过scanf直接输入值到位段成员

      #define _CRT_SECURE_NO_WARNINGS
      #include <stdio.h>

      struct A {
      int _a : 2;
      int _b : 5;
      int _c : 10;
      int _d : 30;
      };

      int main()
      {
      struct A sa = { 0 };
      scanf("%d", &sa._b);//这是错误的
      //正确的⽰范
      int b = 0;
      scanf("%d", &b);
      sa._b = b;
      return 0;
      }

      2、取值范围限制

              位段成员的取值范围由其占用的比特位数决定,超出范围的值会被自动截断,仅保留低位。

              _a:2 的取值范围为 0-3(2 比特最多表示 4 种状态),若赋值为 10(二进制1010),实际存储为010(十进制 2)。  

              以上即为 自定义类型:结构体 的全部内容,麻烦三连支持一下呗~ 

      赞(0)
      未经允许不得转载:网硕互联帮助中心 » 自定义类型:结构体
      分享到: 更多 (0)

      评论 抢沙发

      评论前必须登录!