C语言一个奇奇怪怪的小细节(定制初始化中的一个坑)

在今天写C代码的过程中,发现了一个奇怪的现象:

假设我们有如下数据结构:
struct AddressMapping
{u64 lba;union{u64 addr;u64 addrPage;struct ScatterIter sgiter;};u64 size;
}__attribute__ ((__packed__));struct ScatterIter{struct ScatterList *head;u16 flag;u16 idx;u32 offset;
};

强调一下,AddressMapping数据结构包含了一个匿名联合体,在该匿名联合体中,又包含了一个结构体。

然后,我想要对这个结构体赋初值,因为这个联合体总长为2个64位的数据,且应该是长这个模样:

7d302a68671f2157884a31d1218fd7c8.png

那么,如果我既想要把sgiter.flag赋值为1,又想要赋值addr字段,实际上从内存角度来说,他们是不是不应该冲突的呢,是的,原理上来说,完全不会存在冲突。

好的,现在我打算将这个union的前64位赋值为data,sgiter.flag赋值为1,请问,你认为以下的赋值方式,是否能达到想要的效果,或者它们各会达到什么样的效果?

case1:

struct AddressMapping stripMapping = {.sgiter.flag = 1,.addr = (u64)data,.size = depth * BLK_SIZE
};

case2:

struct AddressMapping stripMapping = {.addr = (u64)data,.sgiter.flag = 1,.size = depth * BLK_SIZE
};

case3:

struct AddressMapping stripMapping = {.sgiter.flag = 1,.sgiter.head = (u64)data,.size = depth * BLK_SIZE
};

结果可能超乎你想象,以上3个case,将会得到三个结果,它们完全不一样。

对于case1,运行代码后观察到,对于sgiter.flag的赋值失败了,且赋值0,对于case2,运行代码后观察到,对于addr的赋值失败了且赋值0,对于case3,运行代码后观察到,符合我们的需求。

于是我们询问一下高材生ChatGPT,看看它对自己的祖师爷C语言有没有这方面的了解:

问题:我想知道 对于 type a = {.xxx = xxx}这样的赋初值,编译器是如何处理的?

回答是:

对于类似.xxx = xxx这样的赋初值语法,它是由C语言提供的一种结构体初始化语法,通常称为"设计器初始化器"(designated initializer)。

设计器初始化器允许您通过指定结构体成员的名称来选择性地初始化特定成员,而不需要按照结构体定义中成员的顺序进行初始化。这在初始化复杂的结构体时非常有用。

当编译器遇到设计器初始化器时,它会根据指定的成员名称来识别并初始化对应的成员。编译器会使用指定的成员名称来匹配结构体定义中的成员,并为其赋予指定的值。

以下是一个示例说明:

struct ExampleStruct {int a;int b;int c;
};int main() {struct ExampleStruct example = {.b = 2,.a = 1,.c = 3};return 0;
}

在这个示例中,ExampleStruct结构体具有三个整型成员abc。在main函数中,通过使用设计器初始化器,我们可以选择性地为结构体的成员赋值。在这种情况下,我们为成员b赋值2,a赋值1,c赋值3。请注意,我们可以以任意顺序指定成员的初始化值。

编译器会根据指定的成员名称和值,将正确的赋值操作应用于对应的结构体成员。这样,您可以通过设计器初始化器来初始化结构体的特定成员,而不需要关心成员在结构体定义中的顺序。

需要注意的是,设计器初始化器是C99标准引入的特性,因此旧版本的编译器可能不支持该语法。请确保您的编译器支持C99标准或更高版本。

追问:请告诉我更多关于设计器初始化器的信息。

回答:

当使用设计器初始化器时,您可以选择性地为结构体或联合体的成员指定初始化值。这种初始化语法更加灵活,可以按照成员的名称进行初始化,而不需要按照定义的顺序。

以下是一些关于设计器初始化器的更多信息:

  1. 语法格式:设计器初始化器使用大括号({})来表示初始化器,并在其中使用点操作符(.)来指定成员名称和对应的初始化值。语法为:.member = value

  2. 初始化顺序:设计器初始化器允许您以任意顺序指定成员的初始化值。编译器会根据指定的成员名称来匹配并初始化对应的成员。

  3. 重复赋值:在设计器初始化器中,如果多次为同一个成员指定初始化值,最后一次赋值将起作用。这意味着后面的初始化值将覆盖前面的值。

  4. 未指定的成员:如果在设计器初始化器中没有为某个成员指定初始化值,那么该成员将使用其定义时指定的默认值(如果有)进行初始化。对于基本数据类型,未初始化的成员将具有未定义的值。

  5. 嵌套结构体和联合体:设计器初始化器可以嵌套使用,以初始化嵌套结构体或联合体的成员。您可以使用嵌套的设计器初始化器为内部结构体或联合体的成员指定初始化值。

  6. 兼容性:设计器初始化器是C99标准引入的特性,因此旧版本的C编译器可能不支持该语法。请确保使用支持C99或更高版本的编译器。

通过使用设计器初始化器,您可以以更直观和灵活的方式初始化结构体和联合体的成员。这对于具有许多成员或具有复杂嵌套结构的数据结构特别有用。

似乎让我们明白了我们的问题,当对于设计器初始化器(网上有翻译为定制初始化),对于相同成员,只有最后一个起效,addr与sgiter为相同成员,编译器可能会自动略过对前一个的处理。

为了进一步探究这个问题,我又去翻了翻C99标准,里面有这么一句话:

12a1aecbea211fbeffda2d5c33ce94f1.png

翻译过来就是除非另有明确说明,否则就本子句而言,结构和联合类型的对象的未命名成员不参与初始化。结构对象的未命名成员即使在初始化后也具有不确定的值。

也就是说对匿名的联合体赋值似乎是一个未定义行为,照我们的实验来看,更倾向于是略过了相同成员中的前者,直接处理后者。

ChatGPT也给出了解决方案:

在您的情况下,要为addr字段赋值,您需要通过联合体本身进行操作。以下是一种可能的解决方案:

struct AddressMapping mapping = {.lba = 0,  // 为其他字段设置适当的初始值.size = BLK_SIZE
};mapping.addr = (u64)data;
mapping.sgiter.flag = 1;

也就是不要对它初始化,到后面再赋值就好了。

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

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

相关文章

一文看分布式锁

为什么会存在分布式锁? 经典场景-扣库存,多人去同时购买一件商品,首先会查询判断是否有剩余,如果有进行购买并扣减库存,没有提示库存不足。假如现在仅存有一件商品,3人同时购买,三个线程同时执…

最新自动定位版本付费进群系统源码

更新内容: 1.在网站首页增加了付款轮播功能。 2.新增了城市定位功能,方便用户查找所在城市的相关信息。 3.对域名库及支付设置进行了更新和优化。 4.增加了一种图模板设置模式,简化了后台模板设置流程。 5.此外还进行了前后台的其他优化…

ClickHouse的分片和副本

1.副本 副本的目的主要是保障数据的高可用性,即使一台ClickHouse节点宕机,那么也可以从其他服务器获得相同的数据。 Data Replication | ClickHouse Docs 1.1 副本写入流程 1.2 配置步骤 (1)启动zookeeper集群 (2&…

【蓝桥杯省赛真题01】C++水下探测器 第十届蓝桥杯中小学生创意编程大赛C++编程比赛省赛真题解析

目录 C/C++水下探测器 一、题目要求 1、编程实现 2、输入输出 二、算法分析

uniapp-轮播图点击预览功能

实现效果 点击后打开预览图 实现代码 <swiper v-if"this.bannerList.length > 1" class"swiper" autoplay"true" duration"500" interval"2000" change"changeSwiper"><swiper-item class"swip…

WordPress网站迁移实战经验

前几日,网站服务器到期,换了服务商,就把我的WordPress的网站迁移到本地电脑了。方便以后文章迁移。 本次迁移网站主要经历以下几个步骤。 1.域名转出。 2.备份数据库及网站文件下载。 3.重新搭建WordPress网站。 4.网站文件及数据库导入。 下面详细介绍下每个步骤的操作…

一些RLHF的平替汇总

卷友们好&#xff0c;我是rumor。 众所周知&#xff0c;RLHF十分玄学且令人望而却步。我听过有的小道消息说提升很大&#xff0c;也有小道消息说效果不明显&#xff0c;究其根本还是系统链路太长自由度太高&#xff0c;不像SFT一样可以通过数据配比、prompt、有限的超参数来可控…

揭示高防CDN的局限性与探讨其小众化原因

在网络安全领域&#xff0c;高防CDN&#xff08;高防御内容分发网络&#xff09;被认为是保护网站免受恶意攻击的强大工具&#xff0c;然而&#xff0c;尽管其在防护方面表现卓越&#xff0c;高防CDN在广泛应用中仍然相对小众。本文将从高防CDN的局限性出发&#xff0c;深入探讨…

智能配电房管理系统

智能配电房管理系统依托电易云-智慧电力物联网&#xff0c;是一种集成了互联网、物联网、大数据、人工智能等先进技术的管理系统&#xff0c;专门用于配电房的智能化管理和运维。以下是智能配电房管理系统的主要功能和特点&#xff1a; 一、主要功能&#xff1a; 实时监测与数据…

【大模型应用开发教程】动手学大模型应用开发,一起探索LLM Universe

动手学大模型应用开发 01 开源初心02 教程内容03 学习指南04 文章最后 原文链接-奇想星球 LLM 正逐步成为信息世界的新革命力量&#xff0c;其通过强大的自然语言理解、自然语言生成能力&#xff0c;为开发者提供了新的、更强大的应用开发选择。随着国内外井喷式的 LLM API 服…

【LeetCode刷题日志】20.有效的括号

&#x1f388;个人主页&#xff1a;库库的里昂 &#x1f390;C/C领域新星创作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏✨收录专栏&#xff1a;LeetCode 刷题日志&#x1f91d;希望作者的文章能对你有所帮助&#xff0c;有不足的地方请在评论区留言指正&#xff0c;…

【广州华锐互动】VR可视化政务服务为公众提供更直观、形象的政策解读

虚拟现实&#xff08;VR&#xff09;技术正在逐渐应用于政务服务领域&#xff0c;为公众提供更加便捷、高效和个性化的服务体验。通过VR眼镜、手机等设备&#xff0c;公众可以在虚拟环境中参观政务服务中心&#xff0c;并根据自己的需求选择不同的办事窗口或事项进行咨询和办理…