结构体的深入了解(下)

1.修改默认对齐数

在之前我们了解到在vs中的默认对齐数为8,在gcc下没有默认对齐数的,那我们能否在vs上进行修改呢?我们来试一下:(#pragma 这个预处理指令,可以改变编译器的默认对齐数)


#include <stdio.h>
#pragma pack(1) //设置默认对⻬数为1
struct S
{char c1;int i;char c2;
};
int main()
{struct S s;size_t ret =sizeof(s);printf("%zd", ret);return 0;
}

在之前我们的这串代码结果为12,现在结果为6,虽然我们通过修改默认对齐数,而减少空间的浪费,但是我们编译器在寻找相对应的数据时也会浪费时间。这与我们了解结构体的对齐的作用相同。当我们要修改回默认对齐数时只需要再次输入#pragma pack(),即可。括号里为空。

2. 结构体传参

在之前的代码学习时,我们了解到可以将结构体整体传入,也可以传地址,但是这两种方法哪一种更好呢?当然是传地址了,因为我们传整个结构体的话,会多占用一份形参所申请的空间。

演示如下:

#include <stdio.h>
struct S
{char name[20];int age;
};void print1(struct S s[3])
{for (int i = 0; i < 3; i++){printf("%s %d ", s[i].name, s[i].age);}}void print2(struct S *pt){for (int i = 0; i < 3; i++){printf("%s %d ", pt->name, pt->age);pt++;}
}
int main()
{struct S s[] = { {"zhang",18, } ,{"li",12},{"wang",24} };print1(s);printf("\n");print2(&s);return 0;
}

这里的print2就是采用传地址的方式,函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。所以结构体传参最好使用传地址的方式。

 3 .结构体实现位段

1.什么是位段

1. 位段的成员必须是 int、unsigned int 或signed int ,在C99中位段成员的类型也可以
选择其他类型。
2. 位段的成员名后边有一个冒号和一个数字。

结构体位段的出现是为了节省空间。

#include<stdio.h>
struct S
{char a:2 ;int b:20  ;int c:2  ;};
int main()
{struct S s;printf("%zd ", sizeof(s));return 0;
}

这个结构体原来占用12个字节,现在占用多少个呢?

运行结果:

2.位段的内存分配


1. 位段的成员可以是 int  unsigned int  signed int 或者是 char 等类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

在不同编译器上位段的内存申请可能不同,下面我们来看下在vs上位段的内存申请是怎么样的?

struct S
{
char a:3;
char b:4;
char c:5;
char d:4;
};
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;

 在内存中的表示:

为啥会是62 03 04 呢?我们来分析一下:

首先a我们给了它三个bit位,需要它存储的数字是10,10 的二进制为1010,存不下,发生截断只能存入010,b我们需要它存储的数字是12,它的二进制为1100也可以存下。以此内推,c中存的是00011,d中就是0100,我们一开始申请4个字节。

我们假设从右往左开始存放,如果后续空间不够就重新申请空间:一个字节一个字节的申请

 我们再一个字节一个字节的算,就是62 03 04,所以假设成立。这就是在vs中申请内存的方式。

(在位段中也存在对齐现象)

 3.位段的跨平台问题

1. int位段被当成有符号数还是无符号数是不确定的。
2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会
出问题。
3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃
剩余的位还是利用,这是不确定的。

4.位段的应用


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

位段使用的注意事项


位段的几个成员共有同一个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位置处是没有地址的。内存中每个字节分配一个地址,一个字节内部的bit位是没有地址的。
所以不能对位段的成员使用&操作符,这样就不能使用scanf直接给位段的成员输入值,只能是先输入放在一个变量中,然后赋值给位段的成员。

演示如下:

#include<stdio.h>
struct S
{char a : 3;char b : 4;
};int main()
{int n = 0;struct S s = { 0 };scanf("%d", &n);s.a = n;return 0;
}

这样就可以在不拿到位置的情况下,赋值了。

谢谢

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/456824.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

信号系统之滤波详解

1 过滤的基础 通常希望使用信号的幅度&#xff0c;而不是它的功率。例如&#xff0c;假设一个增益为20dB的放大器。根据定义&#xff0c;这意味着信号中的功率增加了 100 倍。由于幅度与功率的平方根成正比&#xff0c;因此输出幅度是输入幅度的 10 倍。虽然 20dB 意味着功率的…

基于SSM的实习管理系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的实习管理系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring Spri…

基于A-Star搜索算法的迷宫小游戏的设计

这篇文章是作者人工智能导论课的大作业&#xff0c;发出来供大家学习参考&#xff08;有完整代码&#xff09;。想要论文WORD文件的可以在本文资源处下载&#xff08;可能还在审核&#xff09;。 摘要&#xff1a; 本文章聚焦于基于A-Star搜索算法的迷宫小游戏设计&#xff0c;…

时序数据库Influxdb查询多个字段_field同一时间的值,组成一条数据

Influxdb将表格数据多个字段_field从垂直列布局聚合成水平布局行字段。 问题 1、Influxdb 是一种时间序列数据库&#xff0c;在我的项目中主要用来存储换热站的测点数据的。换热站有非常多的测点&#xff0c;我们用Flux 语法去查询测点数据&#xff0c;返回的数据结构是每个测…

[C++] 如何使用Visual Studio 2022 + QT6创建桌面应用

安装Visual Studio 2022和C环境 [Visual Studio] 基础教程 - Window10下如何安装VS 2022社区版_visual studio 2022 社区版-CSDN博客 安装QT6开源版 下载开源版本QT Try Qt | 开发应用程序和嵌入式系统 | Qt Open Source Development | Open Source License | Qt 下载完成&…

Linux 分析指定JAVA服务进程所占内存CPU详情

1、获取服务进程PID [rootVM-32-26-centos ~]# service be3Service status Application is running as root (UID 0). This is considered insecure. Running [25383]2、获取进程占用详情 [rootVM-32-26-centos ~]# cat /proc/25383/status Name: java Umask: 0022 State: S…

企业邮箱是什么?企业邮箱百科

本文将为大家讲解&#xff1a;1、企业邮箱的定义&#xff1b;2、企业邮箱的主要功能特点&#xff1b;3、企业邮箱如何选择和部署&#xff1b;4、企业邮箱的运营与维护&#xff1b;5、企业邮箱在实际工作中的应用与挑战&#xff1b;6、2024年最新五大企业邮箱盘点   下面提到的…

《计算机网络简易速速上手小册》第5章:无线网络和移动通信(2024 最新版)

5.1 WLAN的工作原理 - 揭秘无线局域网络的魔法 5.1.1 基础知识 无线局域网络&#xff08;WLAN&#xff09;允许设备通过无线方式连接到一个局部区域网络&#xff0c;主要基于IEEE 802.11标准&#xff0c;俗称Wi-Fi。WLAN的核心是无线路由器&#xff0c;它不仅充当着网络中各设…

记录一次centos 使用selenium运行环境

这里写自定义目录标题 宝塔面板 安装 selenium安装google-chrome 宝塔面板 安装 selenium 安装google-chrome yum install https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm 查看chrome版本 google-chrome --version 下载对应chrome版本的chro…

宠物空气净化器哪个品牌质量好?实惠的猫用猫用净化器牌子测评

作为宠物主人&#xff0c;我们深知养宠物的乐趣和责任&#xff0c;但同时也面临着一些挑战&#xff0c;比如宠物脱毛、气味和室内空气质量等问题。正因如此&#xff0c;越来越多的家庭选择宠物空气净化器&#xff0c;为我们营造一个清新、健康的居住环境。 无论我们多么喜欢我…

C语言基础语法..

1.函数的基本语法 函数的格式为&#xff1a; 返回值类型 函数名(参数列表){ 函数体(包括返回值语句) } 利用上述的格式 我们可以自己整一个实现加法功能的函数 int add(int a, int b){return a b; } int main(){int c add(10, 20);printf("%d", c);// 30return …

高亮显示不一致

先准备好测试文件 [rootnode4 ~]# cat 2.1 No. Table Name Src Count Des Count Result 1 sbtest1 100 100 PASS 2 sbtest2 200 300 NOTPASS 3 sbtest3 150 150 …