C语言常见的自定义数据类型(1)—— 结构体

2023-05-16

目录

1、结构体

1.1 结构体的定义

1.2 结构体的自引用

1.3 结构体类型的重命名

1.4 结构体的嵌套

2、结构体大小的计算

2.1 结构体内存对齐

2.2 嵌套结构体大小的计算

2.3 offsetof函数

2.4 修改默认对齐数

2.5 结构体内存对齐的意义

3、结构体传参

①结构体传参

②结构体地址传参

4、位段

4.1 什么是位段

4.2 位段的内存分配

4.3 位段的跨平台问题

4.4 总结:


在C语言中,常见的数据类型有整型int、浮点型float、字符类型char等,而仅仅用这些简单的数据类型来描述现实世界是远远不够的,如描述一本书时,要想通过定义一个变量涵盖这本书的名字,出版社,作者等信息,只用简单的数据类型是不能实现的,因此,C语言还规定了几个常见的自定义类型:结构体、枚举、联合体。

1、结构体

1.1 结构体的定义

C语言中,可以使用结构体来实现存放一组不同类型的数据。结构体也可以认为是一些值的集合,这些值称为成员变量,结构体的每个成员可以是不同类型的变量。

struct tag
{
	member list;//成员列表
}variable list;//变量列表

如对一个学生的姓名、年龄、成绩进行描述时定义的结构体:

#include<stdio.h>
struct Stu
{
	char name[20];//成员变量
	int age;
	double score;
};

int main()
{
	struct Stu s1;//定义一个结构体变量s1
return 0;
}

1.2 结构体的自引用

如果有五个节点分别为1 ,2 ,3, 4 ,5 ...... 如果要像顺序表一样,按照一个线性的关系把它存起来,即通过1可以找到2,通过2找到3 ...... ,以此类推。可以把2节点的地址存到1节点,把3节点的地址存到2节点 ...... ,以此类推,在最后一个节点处存放空指针。如下定义了一个链表式的结构体:

#include<stdio.h>
struct Node
{
	int data;//数据域
	struct Node* next;//指针
};
int main()
{
	struct Node n;

return 0;
}

1.3 结构体类型的重命名

与其他数据类型一样,结构体类型的重命名同样可以用typedef来实现:

#include<stdio.h>
typedef struct Node
{
	int data;//数据域
	struct Node* next;//指针
}Node;

int main()
{
	struct Node n1;
	Node n2;
	//n2和n1的类型是一样的

return 0;
}

1.4 结构体的嵌套

如下列代码,在结构体 struct Node 里又嵌套了结构体 struct Book:

#include<stdio.h>
struct Book
{
	char name[20];
	float price;
	char id[12];
}s={"加油",55.5f,"haha001"};

struct Node
{
	struct Book b;
	struct Node* next;
};

int main()
{
	//struct Book s2={"努力",55.3f,"yeah002"};//也可以这样创建结构体变量
	struct Node n={{"gogogo",89.2f,"lyd"},NULL};

return 0;
}

2、结构体大小的计算

有如下两个结构体 S1、S2 :

struct S1
{
    char c1; 
    int i; 
    char c2; 
};

struct S2
{
    char c1; 
    char c2; 
    int i; 
};

它们的成员列表相同,而排列顺序不同,由简单数据类型的大小可知,char 类型占一个字节,int 类型占4个字节,这样我们可以简单估算两个结构体的大小为6个字节,实际上真的会是这样吗?下面利用 sizeof 来进行检验计算:

#include<stdio.h>
struct S1
{
	char c1;
	int i;
	char c2;
};
struct S2
{
	char c1;
	char c2;
	int i;
};
int main()
{
	struct S1 s;
	struct S2 s2;
	printf("%d\n",sizeof(s)); //12
	printf("%d\n",sizeof(s2)); //8

return 0;
}

可以发现,在内存中S1结构体占12个字节大小,S2结构体占8个字节的大小,那么是什么原因导致这样的结果呢?

2.1 结构体内存对齐

结构体对齐规则:

1、第一个成员在与结构体变量偏移量为0的地址处。

2、其他成员变量要对齐到对齐数的整数倍的地址处。

(对齐数 = 编译器默认的一个对齐数与该成员大小的较小值(VS默认的值为8))

3、结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

4、如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

这样,我们再看上面的S1和S2结构体:

struct S1
{
    char c1; 
    int i; 
    char c2; 
};

对结构体S1:假设这个结构体在一个位置处开辟空间要存储,第一个成员c1在与结构体变量偏移量为0的地址处,即在0处;对第二个成员变量,对齐到对齐数的整数倍的地址处,4与8比较4较小,4是对齐数,所以i放到(4的倍数)与结构体变量偏移量为4的地址处,占4个字节,c2为1个字节,1与8比较1较小,1是对齐数,所以c2放到与结构体变量偏移量为8的地址处。又因为结构体总大小为最大对齐数的整数倍,4与1相比,4为最大对齐数,所以现在总共占了9个字节的大小,不是4的倍数,所以还要继续开辟3个字节的空间,即12个字节的空间,所以这个结构体的大小为12个字节。

struct S2
{
    char c1; 
    char c2; 
    int i; 
};

同理对结构体S2:假设这个结构体在一个位置处开辟空间要存储,第一个成员c1在与结构体变量偏移量为0的地址处,即在0处;对第二个成员变量,对齐到对齐数的整数倍的地址处,1与8比较1较小,1是对齐数,所以c2放到(1的倍数)与结构体变量偏移量为1的地址处,占1个字节,i为4个字节,4与8比较4较小,4是对齐数,所以i放到与结构体变量偏移量为4的地址处。又因为结构体总大小为最大对齐数的整数倍,4与1相比,4为最大对齐数,现在总共占了8个字节的大小,是4的倍数,所以这个结构体的大小为8个字节。

2.2 嵌套结构体大小的计算

看下面代码,在结构体S4中嵌套了结构体S3,求S4结构体的大小:

#include<stdio.h>
#include<stddef.h>
struct S3
{
	double d;
	char c;
	int i;
};
struct S4
{
	char c1;
	struct S3 s3;
	double d;
};

int main()
{
	printf("%d\n",sizeof(struct S4));//32

return 0;
}

根据结构体对齐规则第四条,如果有嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

c1大小为1字节,放到与结构体变量偏移量为0的地址处,S3可知为16字节大小,对齐到8(嵌套的结构体对齐到自己的最大对齐数的整数倍处)地址处,d大小为8字节,对齐到24地址处,此时总共占了32字节,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍,32是8的整数倍,所以S4大小即为32字节。

2.3 offsetof函数

——计算结构体成员相对于起始位置的偏移量

size_t offsetof( structName, memberName );

该函数的两个参数分别为结构体名和成员名,头文件为:<stddef.h>。

#include<stdio.h>
#include<stddef.h>
struct S3
{
	double d;
	char c;
	int i;
};

struct S2
{
	char c1;//1
	char c2;//1
	int i;///4
};

int main()
{
	printf("%u\n",offsetof(struct S3,d)); //0
	printf("%u\n",offsetof(struct S3,c)); //8
	printf("%u\n",offsetof(struct S3,i)); //12
	//printf("%d\n",sizeof(struct S3)); //16

	printf("%u\n",offsetof(struct S2,c1)); //0
	printf("%u\n",offsetof(struct S2,c2)); //1
	printf("%u\n",offsetof(struct S2,i)); //4
return 0;
}

2.4 修改默认对齐数

上面介绍到,在VS编译器中默认对齐数为8(linux环境下没有默认对齐数,此时自身的大小就是其对齐数),在对齐方式不合适的时候,我们可以更改默认的对齐数。

利用#pragma pack( )修改默认对齐数:

#include<stdio.h>

#pragma pack(4) //设置
//#pragma pack(1)----9    改成1时实际上就是按照不对齐方式存储的
struct S
{
	char c;
	double d;
};

#pragma pack() //取消

int main()
{
	struct S s;
	printf("%d\n",sizeof(s));//12

return 0;
}

可知,当修改默认对齐数为1时,结构体大小变为9字节,此时就是按照不对齐方式存储的;当修改默认对齐数为4时,此时结构体大小变为12字节。

2.5 结构体内存对齐的意义

1. 平台原因(移植原因):

并不是所有的硬件平台都能访问任意地址上的任意数据的,某些硬件平台只能在某些地址处(比如说只能在4的倍数地址处访问)取某些特定类型的数据,否则抛出硬件异常。

2、性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。为了访问未对齐的内存,处理器需要作两次内存访问,而对齐的内存访问仅需要一次访问就可以。

总的来说,结构体内存对齐是拿空间来换取时间的做法。在上面的代码中,改了下成员的顺序,开辟的空间就不一样了。所以,在设计结构体的时候,如果考虑既要满足对齐,又要节省空间,可以让占用空间小的成员尽量集中在一起(这样在一定程度上浪费的空间就会更少)。

3、结构体传参

比较下列结构体传参的两种方式:

①结构体传参

#include<stdio.h>
struct S
{
	int data[1000];
	int num;
};

void print1(struct S s)
{
	printf("%d\n",s.num);
}

int main()
{
	print1(s);//传结构体

return 0;
}

②结构体地址传参

#include<stdio.h>
struct S
{
	int data[1000];
	int num;
};

void print2(struct S* ps)
{
	printf("%d\n",ps->num);
	printf("%d\n",(*ps).num);
}

int main()
{
	print1(&s);//传结构体地址

return 0;
}

以上两种方式都可以实现对结构体成员信息的打印。不过,函数在传参的时候,参数是需要压栈的,会有时间和空间上的系统开销。第一种方式把整个结构体传参,如果结构体过大,参数压栈的时候系统开销比较大,会导致系统性能的下降;而第二种方式只需要传一个指针,而指针的大小是固定的,4字节(32位平台)或者8字节(64位平台),所以结构体传参的时候,尽量传结构体的地址。

4、位段

了解了结构体,就不得不提结构体实现位段的能力了。

4.1 什么是位段

位段的声明和结构体是类似的,注意有两处不同:

1. 位段的成员必须是 int 、unsigned int 或 signed int (char 其实也可以)

2. 位段的成员名后边有一个冒号和一个数字,数字代表占用 bit 位的数量

比较结构体和位段的不同:

结构体:

//结构体
struct A
{
	int _a;
	int _b;
	int _c;
	int _d;
};

位段:

//位段
struct B
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};

对于结构体A,如果不考虑对齐,结构体A需要4个整型即16个字节的内存;对于位段B,_a这个成员只需要占2个bit位,_b这个成员占5个bit位,_c这个成员占10个bit位,_d这个成员占30个bit位,总共只要47个bit位,所以只用两个整型空间即可存下:

#include<stdio.h>
//结构体
struct A
{
	int _a; //一个整型的取值范围为INT_MIN ~ INT_MAX
	int _b;
	int _c;
	int _d;
};

//位段
struct B
{
	int _a : 2; //2个比特位 只能放 00 01 10 11 四个数, 如果有一个变量正好只有这几个取值,可以考虑用位段
	int _b : 5;
	int _c : 10;
	int _d : 30;
};
int main()
{
	printf("%d\n",sizeof(struct A)); // 16   
	printf("%d\n",sizeof(struct B)); // 8    ---- 确实只需要两个整型的空间
return 0;
}

注意:

结构体A中的整型成员_a,取值范围为INT_MIN ~ INT_MAX;

位段B中的成员_a由于只占两个bit位的大小,意味着只能放 00 ,01 ,10, 11 四个数。

所以在定义结构体的时候,如果发现某些成员是不需要那么大的空间的,只需要少量的bit位就够了,这个时候使用位段在一定程序上节省了空间。

4.2 位段的内存分配

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

对这个位段(均为int),在内存存储的时候,先开辟了一个int类型的空间,即4个字节,先存_a,占了2个bit位,还有30个,再存_b,又占了5个bit位,还剩25个bit位,再存_c,还剩15个bit位,再存_d的时候,空间不够了,考虑再开辟一个int类型的空间,就能放下_d了。

此时考虑一个问题:放_d的时候是接着后面放还是在新开辟的那个int类型里的空间去放?

假设存储的时候从低位开始,空间不够了在新开辟的空间去存,不够的空间浪费掉,最后推算的应该是需要3个字节,下面用一个例子去验证:

#include<stdio.h>
struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
int main()
{
	struct S s = {0};
	printf("%d\n",sizeof(s)); // 3

return 0;
}

由打印结果可知,我们的推断是正确的,确实是3字节。

4.3 位段的跨平台问题

在使用位段的时候,同时要注意:

1. 由于 int 位段被当成有符号数还是无符号数是不确定的;

2. 位段中最大位的数目也是不确定的 (16 位机器最大16,32 位机器最大 32,如果写成27,在16位机器会出问题);

3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义(VS中从右向左分配);

4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这也是不确定的。

由于以上的不确定性,造成了位段有跨平台的问题。

4.4 总结:

1. 位段的成员可以是int 、 unsigned int 、  signed int 或是char(属于整型家族)类型
2. 位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的

3. 在VS环境下:位段的在内存中的空间开辟与存储规则是:当存不下的时候开辟空间,放的时候直接在新开辟的空间里去存,之前放不下的空间就浪费掉了

4. 与结构相比,位段可以很好的节省空间,但是有跨平台的问题所在,注重可移植的程序应该避免使用位段

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言常见的自定义数据类型(1)—— 结构体 的相关文章

  • Vuex速学篇:(1)基本套路

    我们前面做了一个这样的页面 xff0c 为了增加我们的学习难度 xff0c 我们特意拆分成了不同的组件 我们知道 xff0c 我们在子组件里并不能直接对兄弟组件里的属性进行操作 xff0c 我们通过this emit 调用父组件的方法 xf
  • ElementUI案例演示:导航、布局、加载动画

    知识点 1 vue router之嵌套路由 http router vuejs org zh cn essentials nested routes html 2 element ui 导航组件 布局组件 加载动画 http element
  • ElementUI之表单验证、数据绑定、路由跳转

    1 新建表单组件el form vue span class hljs tag lt span class hljs title template span gt span span class hljs tag lt span class
  • vue-router: 嵌套路由

    模板抽离 我们已经学习过了Vue模板的另外定义形式 xff0c 使用 lt template gt lt template gt span class hljs comment lt 模板抽离出来 gt span span class hl
  • react.js的两种路由方式:HashRouter

    react js路由 初步 前面我们已经了解了react js其中一种路由方式 这种方式是利用 html5的 span class hljs escape 96 w span indow history span class hljs es
  • 入手python绘图包:matplotlib,画直线、画抛物线

    入手python绘图包 xff1a matplotlib 官方地址 xff1a http matplotlib org github地址 xff1a http github com matplotlib matplotlib 学习一款图形化
  • 使用CMake构建OpenCV项目

    上一篇文章中 xff0c 我们介绍了如何在ubuntu上安装配置OpenCV xff0c 这篇文章我们来对我们的安装进行测试 xff0c 并介绍如何用CMake工具快捷地构建OpenCV项目 项目结构 为了使整个项目更加条理 xff0c 我
  • Ubuntu连接不了网络的解决方法亲测可行经验

    突然发现Ubuntu连不上网络 xff0c 网络打问号或者右上角也没有网络图标 xff1b 楼主一般通过前两步就解决了 xff0c 大家自行查阅网络服务名称 xff0c OK直接进入正题 通过命令行方式重启网络 如果你使用的 Ubuntu
  • 解决 ImportError: C extension: No module named ‘pandas._libs.tslib‘ not built.

    yolo配置 报错 nvidia 64 nx yolov5 master python3 detect py Traceback most recent call last File 34 usr lib python3 dist pack
  • python subprocess获取stdout和stderr

    本文转载自http www firefoxbug com index php archives 2419 xff0c 如有版权问题请联系博主删除 用subprocess的时候 xff0c 怎么获取stdout和stderr xff1f 下面
  • 关于Libcurl双向认证请求https

    之前通过libcurl开发只是做http请求 xff0c 这次公司项目需要请求https xff0c 所以就研究了一下 xff0c 其实用libcurl做http请求是非常简单的 xff0c 所有底层实现都被封装到了libcurl里面 xf
  • Kubernates简介

    Kubernates简介 应用程序的开发部署变化 从单体应用到微服务 单体应用的缺点 由多个彼此耦合的组件组成 开发 部署 管理必须以同一个实体进行 即使对某个组件的小修改也需要重新部署整个应用 组件之间没有严格的边界定义 相互依赖 随着功
  • pipenv 无法获取系统环境变量

    今天遇到了一个有意思的问题 项目是使用pipenv作为虚环境来进行包管理的 xff0c 今天在windows server 2012R2和windows server 2016上发现python脚本在运行的过程中 xff0c 不能读取到系统
  • 创客基地oDrive第二课 X2212电机配置

    淘宝套装链接 B站视频链接 2021年3月31日前 入Q群 xff08 732557609 xff09 可抽奖oDrive主板 xff01 B站视频 创客基地oDrive第二课 X2212电机配置 第1部分 硬件介绍 1 1 硬件清单 oD
  • Makerbase X2212电流环(转矩)配置

    该配置基于X2212电机 xff0c 控制模式为电流环 xff08 转矩 xff09 模式 主板参数 电机参数 编码器参数配置和位置环控制一样 xff0c 已配置可直接跳转到控制器配置 xff0c 没有配置的按以下步骤配置 1 恢复默认参数
  • Postman -中文版-安装教程

    一 下载 安装 Postman 下面是历史版本的下载链接地址 请把链接中的 34 版本号 34 替换为指定的版本号 xff08 根据自己的需求变更 xff09 Windows64位 xff1a https dl pstmn io downl
  • HTTP Digest authentication

    Digest authentication xff09 是一个简单的认证机制 xff0c 最初是为 HTTP 协议开发的 xff0c 因而也常叫做 HTTP 摘要 xff0c 在 RFC2671 中描述 其身份验证机制很简单 xff0c 它
  • ubuntu离线安装Gcc、G++、Make

    前期准备 xff1a 由于GCC G 43 43 Make等工具依赖项众多 xff0c 我们需要提前先把基础依赖库下载并安装 xff0c 才能安装以上工具 工具安装包或基础依赖库下载参加以下Ubuntu官网链接 xff1a xff08 注意
  • 教你轻松在Ubuntu 部署yolov5,胎儿级教程

    环境 xff1a Jetson xavier nx Ubuntu 18 04 python3 8 一 yolov5安装 git clone https codechina csdn net mirrors ultralytics yolov
  • LWIP之lwip_select函数

    代码如下 xff1a Processing exceptset is not yet implemented int lwip select int maxfdp1 fd set readset fd set writeset fd set

随机推荐

  • ubuntu下的c++编译

    刚开始使用ubuntu下的g 43 43 编译c 43 43 程序 xff0c 这里只是简单说以下自己的一些小小感受吧 1 环境准备 在ubuntu中要想编译c程序可以安装gcc编译器 xff0c 编译c 43 43 的话就不能使用gcc了
  • c++ vector的用法

    vector是STL的动态数组 xff0c 可以在运行中根据需要改变数组的大小 因为它以数组的形式储存 xff0c 所以它的内存空间是连续的 vector的头文件为 include lt vector gt 常用方法 xff1a 1 vec
  • 使用python将数据导出excel表格

    python可用于数据分析 xff0c 有时候获得了数据需要导出以作其他作用 本文就介绍python导出excel表格的方法 导出excel表格 xff0c python提供了两个库 xff1a xlwt xlrd 本文只讨论下大致框架 s
  • matlab制作散点图及颜色调配

    散点图也是比较常用的数据分析图 xff0c 今天来聊聊用matlab如何画一个散点图出来 xff01 在matlab中 xff0c 对应散点图的函数是scatter 参数形式为scatter 横坐标 xff0c 纵坐标 xff0c 颜色 x
  • matlab——修改图中字体

    在画图的时候 xff0c 我们可以使用xlabel命名x轴的名字 xff0c 使用ylabel命名y轴的名字 xff0c 使用legend命名变量的名字 xff0c 使用title命名图片的标题 但标题的字体 xff0c 大小都是默认的 其
  • python绘制热力图

    在python中绘制热力图大致有两种方法通过matplotlib库的imshow函数以及seaborn库的heatmap函数 xff0c 通过笔者尝试 xff0c seaborn库更加灵活 xff0c 本篇以seaborn为准 源代码如下
  • 基址寻址和变址寻址区别(白话版)

    在寻址方式里面 xff0c 基址寻址和变址寻址是比较常用的两种寻址方式 但因为两种太像了 xff0c 总是搞不清楚 上网查到的描述太过专业看起来特别吃力 写这篇 xff0c 希望能用一种通俗易懂的方式对二者做个区分 为什么总容易搞混呢 xf
  • ROS修改pkg名和node名教程

    修改pkg名 有的时候最开始起了一个功能包package名 xff0c 但后来要进行修改 修改package名 xff0c 需要改两步然后重新catkin make即可 操作如下 xff1a 再回到工作空间执行catkin make即可 参
  • ROS-TCP-Connector and ROS-TCP-Endpoint

    Unity官方提供了和ROS交互的接口 xff1a ROS TCP Connector and ROS TCP Endpoint 有了这两个Unity就能够更好的和真实机器人做交互 两个接口的实现基于ROS ros bridge xff0c
  • Python 使用can模块(记录稿)

    直接安装 xff1a pip install python can 如果报这个错 更新一下pip pip3 install upgrade pip 或者是 pip install upgrade pip 再安装wrapt pip insta
  • Android Studio报错:W/System.err: java.net.SocketException: socket failed: EPERM (Operation not permitt

    解决方案 xff1a 在AndroidManifest xml中增加 xff1a span class token operator lt span uses span class token operator span permissio
  • C++简单实现http服务端客户端传输实例

    使用本代码有两个注意事项 xff1a 代码使用到了httplib库 xff0c 需要下载然后把 h文件放到自己的目录下 httplib下载地址 xff1a https gitcode net mirrors yhirose cpp http
  • VSCODE连接vmware虚拟机

    有时候想用VSOCDE中的ssh连接虚拟机 桥接模式 的终端进行操作 xff0c 但是执行ssh命令后总是报错 xff1a Could not connect to span class token number 192 168 span
  • 字符串加密工具

    可用于密码加密 xff0c 代码上阵 xff1a package com util import java security MessageDigest import java security NoSuchAlgorithmExcepti
  • 【RPLIDAR】ubuntu18.04安装cartographer源码并使用RPLIDAR A2M8 - R4建图

    1 创建工作空间 mkdir cartographer ws cd cartographer ws wstool init src 2 下载cartographer源码包 wstool merge t src https raw githu
  • 《C++ Primer Plus》学习笔记——第一章 介绍C++

    C 43 43 在C语言的基础上添加了面向对象编程和泛型编程 C 43 43 继承了C语言高效 简洁 快速和可移植性的传统 C 43 43 比C多了两样编程方法 xff0c 这使得它功能强大 xff0c 同样也意味着使用者需要学习更多的内容
  • 【转载】理解SIP的认证

    理解SIP的认证 From http blog sina com cn s blog 4b839a1b01000bqq html 1 认证和加密 认证 xff08 Authorization xff09 的作用在于表明自己是谁 xff0c
  • 尝试使用绕线法制作数字电路

    最近在学习电路制作的过程中 xff0c 发现使用洞洞板 xff0c 很难处理好具有很多复杂引脚的集成电路 用 锡接走线法 的话 xff0c 集成电路不能太多太复杂 xff0c 否则板子上很难排开 也可以用比较细的导线 xff0c 飞线焊接
  • 用C语言实现一个简单的HTTP客户端(HTTP Client)

    用C语言实现一个简单的HTTP Client xff08 HTTP客户端 xff09 作者 xff1a gobitan xff08 雨水 xff09 日期 xff1a 2007 04 03 转载请注明出处 http blog csdn ne
  • C语言常见的自定义数据类型(1)—— 结构体

    目录 1 结构体 1 1 结构体的定义 1 2 结构体的自引用 1 3 结构体类型的重命名 1 4 结构体的嵌套 2 结构体大小的计算 2 1 结构体内存对齐 2 2 嵌套结构体大小的计算 2 3 offsetof函数 2 4 修改默认对齐