对于部分副本,我希望使用副本设置匹配字段,但不设置不匹配的字段(即保留其先前的值)。
似乎没有发生。我很好奇为什么以及这是否是一些未定义的行为?
#include <stdio.h>
#define print_base(s) printf("%d %d\n", s.a, s.b)
#define print_extended(s) printf("%d %d %d\n", s.a, s.b, s.c)
typedef struct
{
int a;
int b;
} base;
typedef struct
{
int a;
int b;
int c;
} extended;
int main()
{
base s1 = {1,2};
extended s2 = {0};
extended s3 = {0};
extended s4 = {4,5,6};
extended s5 = {4,5,6};
extended s6 = {7,8,9};
base s7 = {0};
print_extended(s2);
s2 = *(extended*)&s1;
print_extended(s2);
print_extended(s3);
memcpy(&s3, &s1, sizeof(s3));
print_extended(s3);
print_extended(s4);
s4 = *(extended*)&s1;
print_extended(s4);
print_extended(s5);
memcpy(&s5, &s1, sizeof(s5));
print_extended(s5);
/* lossy copy */
print_base(s7);
s7 = *(base*)&s6;
print_base(s7);
return 0;
}
/*
Actual Expected
0 0 0 0 0 0
1 2 1 1 2 0
0 0 0 0 0 0
1 2 1 1 2 0
4 5 6 4 5 6
1 2 1 1 2 6
4 5 6 4 5 6
1 2 1 1 2 6
0 0 0 0
7 8 7 8
*/
答案 0 :(得分:0)
s2 = *(extended*)&s1;
这具有未定义的行为,&s1
处的对象不是通过类型extended*
的指针访问的正确类型。
memcpy(&s3, &s1, sizeof(s3));
这也有未定义的行为,因为您从一个仅sizeof(extended)
字节长的对象中读取sizeof(base)
个字节。
如果你考虑一下,它显然不会像你期望的那样工作。复制extended
结构时,编译器会从源中读取三个单词(即sizeof(extended)
),并将这三个单词复制到目标。它不会复制少于三个单词并保留最后一个单词。你告诉它从地址sizeof(extended)
读取&s1
字节,这正是它的作用。并且最后一个成员被设置为垃圾值,因为您从不属于s1
并且包含一些垃圾值的内存位置读取它。
如果您告诉编译器复制sizeof(base)
个字节,为什么期望编译器复制sizeof(extended)
个字节?如果您不希望它复制更多字节,那么不要告诉它复制更多字节!
答案 1 :(得分:0)
当你使用指针转换从一个内存位置复制到另一个内存位置时,你基本上是“自己动手”
这些陈述:
/some/action
等同于:
s2 = *(extended*)&s1;
s1 = *(base*)&s2;
我认为很清楚为什么从 base * source 复制到 extended * dest 只会覆盖部分数据而反之则会产生灾难性的后果(你有一个超出内存访问权限,可能会覆盖重要数据。)