C语言中两个不同类型的结构体相互赋值

embedded/2025/1/12 12:53:19/

在 C 语言中,如果两个结构体的定义(字段名称、数量、顺序、类型)不一样,就不能直接使用 = 运算符进行整体赋值,需要逐个字段进行赋值或者通过其它手段进行“转换”。


1. 字段一一对应赋值

1.1 手动逐个赋值

假设有如下两个结构体:

typedef struct 
{int  id;char name[20];int  age;
} StuA;typedef struct
{int  stuId;char stuName[20];int  birthYear;
} StuB;

如果想把 StuA 类型变量中的信息赋值给 StuB 类型变量,只能手工逐个字段对照相应含义进行赋值。例如:

void convertAtoB(const StuA *src, StuB *dst)
{// 1) 把 src->id 赋给 dst->stuIddst->stuId = src->id;// 2) 把 src->name 字符数组复制到 dst->stuName//    可以用 strcpy,memcpy 等,但要注意数组长度、是否有字符串结束符 '\0' 等strcpy(dst->stuName, src->name);// 3) 根据需求,假设 age 和 birthYear 之间存在一定关系 //    可能需要额外处理,如:birthYear = 当前年份 - age//    这里仅做简单举例dst->birthYear = 2025 - src->age;
}

然后在调用处:

StuA a = {1001, "Alice", 20};
StuB b;convertAtoB(&a, &b);// 测试打印
printf("b.stuId = %d\n", b.stuId);
printf("b.stuName = %s\n", b.stuName);
printf("b.birthYear = %d\n", b.birthYear);

特点

  • 完全可控,每个字段怎么赋值都可以自己定规则(例如做一些计算、类型转换等)。
  • 写法简单明了,但需要维护多行代码,且结构体字段越多,越繁琐。

1.2 结合结构体内不同字段做适配

有时字段名称或类型并不完全对应,需要在转换时做一些逻辑处理。上面已经演示了把 age 转成 birthYear。这种场景是没有直接通用的“整体复制”方法的,只能手写适配逻辑。


2. 如果结构体布局“完全相同”但名字不同

如果两个结构体字段布局完全一致(包括类型、数量、对齐方式等),只是结构体名字不同,在某些情况下,可以通过 memcpy 来“复制”内存内容。

举个例子:

typedef struct
{int  x;float y;
} MyStructA;typedef struct
{int  x;float y;
} MyStructB;

此时它们的内存布局其实是一模一样的,仅名字不一样。可以用:

#include <string.h>MyStructA a = {1, 2.5f};
MyStructB b;memcpy(&b, &a, sizeof(b)); // 或 sizeof(a) 因为大小一样

然后 b.xb.y 分别与 a.xa.y 值相同。但需要特别注意:如果两个结构体字段类型、对齐方式不一致,或者我们需要对字段进行特殊处理,这种做法就会出问题。


3. 不同结构体之间数组相互幅值

在 C 语言中,如果只是想将两个结构体中的数组相互赋值(拷贝数据),可以使用 `memcpy` 或逐元素拷贝。下面介绍两种常见方式。


假设结构体定义

举例说明,假设我们有如下两个结构体,都含有一个长度相同的数组:

#include <stdint.h>typedef struct
{uint8_t arrA[10];// ... 其他字段
} StructA;typedef struct
{uint8_t arrB[10];// ... 其他字段
} StructB;

并且有对应的结构体变量:

StructA sA;
StructB sB;

现在您只想把 sA 中的数组 arrA 拷贝到 sB 中的数组 arrB


方法一:使用 memcpy 拷贝数组

如果您确定两个数组长度相同,且确实要把所有字节都复制过去,那么最简洁的做法是:

#include <string.h>  // memcpy 所在头文件memcpy(sB.arrB, sA.arrA, sizeof(sB.arrB));
  • sB.arrB: 目标数组的首地址

  • sA.arrA: 源数组的首地址

  • sizeof(sB.arrB): 要复制的数据大小(单位:字节)

这样就完成了从 sA.arrAsB.arrB 的数据拷贝。

关键注意事项

  1. 数组长度需相同
    如果两边数组长度不一致,建议使用 sizeof(最短的数组) 或者确保不会越界访问。

  2. memcpy 与字符串
    如果数组保存的是字符串,需要您手动保证目标数组中是否需要末尾 '\0',或者使用 strcpy(适合以 '\0' 结尾的 C 字符串)。但如果只是普通的数据(字节流),memcpy 就更合适。

  3. memcpy 只做纯字节复制
    它不会考虑任何类型转换或深拷贝结构,只是一份内存到另一份内存的原样复制。


方法二:逐元素拷贝(for 循环)

如果想在复制过程中做一些额外操作、检查或转换,或者两边数组大小并不一样,我们可以使用 for 循环逐元素拷贝。例如:

void copyArray(const StructA *source, StructB *dest, uint8_t length)
{// 这里 length 可以是两个数组中的最小长度,以避免越界for (uint8_t i = 0; i < length; i++){dest->arrB[i] = source->arrA[i];}
}

然后调用时:

copyArray(&sA, &sB, 10); // 假设要拷贝 10 个字节

关键注意事项

  1. 可控性
    在循环中我们可以加判定逻辑、打印、或做任何数据变换,而不必再写额外的循环代码。

  2. 不用担心结构体中其它字段
    只要针对目标数组和源数组进行处理就行,不会影响到结构体的其它部分。


总结

  1. 结构体字段不一样时,必须逐个字段赋值或使用适配函数,把源结构体的各字段对应到目标结构体的字段。
  2. 如果内存布局一模一样,只是名字不同,可以通过 memcpy 整体复制,但是要非常确定二者的字段定义、对齐方式、大小都相同。
  3. 如果两个结构体中数组大小完全相同,且只想做简单的字节复制,推荐使用 `memcpy`
  4. 如果需要额外逻辑处理,或者数组大小不一致,或想逐字节检查,可以使用 for 循环 逐元素赋值。

在大多数场景下,手动一一对应字段仍是最常见且安全的做法。


http://www.ppmy.cn/embedded/153284.html

相关文章

使用 Docker 构建 preboot 交叉编译环境

ASR1606/ASR1603 的 preboot 代码需要在 Linux 环境下编译&#xff0c;通常使用 VMware 或者 VirtualBox 软件创建一个 Linux 虚拟机&#xff0c;在虚拟机中做交叉编译。但 preboot 不是那种需要经常编译的代码&#xff0c;完全可以将 preboot 的编译环境制作成 docker 镜像&am…

求矩阵不靠边元素之和(PTA)C语言

求矩阵的所有不靠边元素之和&#xff0c;矩阵行的值m从键盘读入(2<m<10)&#xff0c;调用自定义函数Input实现矩阵元素从键盘输入&#xff0c;调用Sum函数实现求和。(只考虑float型&#xff0c;且不需考虑求和的结果可能超出float型能表示的范围)。 函数接口定义&#x…

计算机网络 笔记 数据链路层 2

1,信道划分&#xff1a; (1)时分复用TDM 将时间等分为“TDM帧”&#xff0c;每个TDM帧内部等分为m个时隙&#xff0c;m个用户对应m个时隙 缺点&#xff1a;每个节点只分到了总带宽的1/m,如果有部分的1节点不发出数据&#xff0c;那么就会在这个时间信道被闲置&#xff0c;利用…

微信小程序实现拖拽盒子效果

要实现一个当前盒子高度由里面的盒子进行支配高度拖拽的效果 // wxml<view class"exmation-item" wx:elif"{{type4}}"> <view class"exmation-item-drag-box" id"drag-box"> <!-- 内容 --><view class"exm…

Perl语言的软件开发工具

Perl语言的软件开发工具 引言 Perl是一种功能强大且灵活的高级编程语言&#xff0c;自1987年由拉里沃尔&#xff08;Larry Wall&#xff09;创建以来&#xff0c;就广泛应用于文本处理、系统管理、网络编程、Web开发等多个领域。作为一种脚本语言&#xff0c;Perl以其简洁的语…

【C++入门】详解(中)

目录 &#x1f495;1.函数的重载 &#x1f495;2.引用的定义 &#x1f495;3.引用的一些常见问题 &#x1f495;4.引用——权限的放大/缩小/平移 &#x1f495;5. 不存在的空引用 &#x1f495;6.引用作为函数参数的速度之快&#xff08;代码体现&#xff09; &#x1f4…

汽车供应链关键节点:物流采购成本管理全解析

在汽车行业&#xff0c;供应链管理是一项至关重要的任务。汽车制造从零部件的生产到整车的交付&#xff0c;涉及多个环节&#xff0c;其中物流、采购与成本管理是核心节点。本文将深入分析这些关键环节&#xff0c;探讨如何通过供应商管理系统及相关工具优化供应链管理。 一、…

拥抱HarmonyOS之高效使用DevEco

拥抱HarmonyOS之高效使用DevEco 前半年对公司的IM SDK进行了鸿蒙化&#xff0c;半年过去系统已经伴随APP上线应用市场&#xff0c;总结一些适配过程中的经验技巧&#xff0c;希望对大家有用。 1.应用AI翻译代码 IM SDK和普通应用的最大差异是逻辑性代码比较多&#xff0c;使…