在 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->stuId
dst->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.x
和 b.y
分别与 a.x
和 a.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.arrA
到 sB.arrB
的数据拷贝。
关键注意事项
-
数组长度需相同
如果两边数组长度不一致,建议使用sizeof(最短的数组)
或者确保不会越界访问。 -
memcpy 与字符串
如果数组保存的是字符串,需要您手动保证目标数组中是否需要末尾'\0'
,或者使用strcpy
(适合以'\0'
结尾的 C 字符串)。但如果只是普通的数据(字节流),memcpy
就更合适。 -
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 个字节
关键注意事项
-
可控性
在循环中我们可以加判定逻辑、打印、或做任何数据变换,而不必再写额外的循环代码。 -
不用担心结构体中其它字段
只要针对目标数组和源数组进行处理就行,不会影响到结构体的其它部分。
总结
- 结构体字段不一样时,必须逐个字段赋值或使用适配函数,把源结构体的各字段对应到目标结构体的字段。
- 如果内存布局一模一样,只是名字不同,可以通过
memcpy
整体复制,但是要非常确定二者的字段定义、对齐方式、大小都相同。 - 如果两个结构体中数组大小完全相同,且只想做简单的字节复制,推荐使用 `memcpy`。
- 如果需要额外逻辑处理,或者数组大小不一致,或想逐字节检查,可以使用 for 循环 逐元素赋值。
在大多数场景下,手动一一对应字段仍是最常见且安全的做法。
标签:arrB,C语言,幅值,数组,相互,sB,赋值,memcpy,结构 From: https://blog.csdn.net/FCZlll/article/details/145022556