Rich Jahn Rich Jahn - 5 months ago 21
C Question

Can you partially copy an instance of a struct to another of a different type in one statement?

With a partial copy I'd expect to set the matching fields with a copy, but leave the non-matching fields unset (i.e. retain their previous values).

It doesn't seem to happen. I'm curious why and if this is some undefined behavior?

#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
*/

Answer

when you copy from one memory location to another using pointer casts you are basically 'taking matters into your own hands'

These statements:

s2 = *(extended*)&s1;
s1 = *(base*)&s2;

Are equivalent to these:

memcpy(&s2, &s1, sizeof(extended));
memcpy(&s1, &s2, sizeof(base));

I think it is clear why copying from base* source to extended* dest will overwrite only part of the data and the other way around can have disastrous consequences (you have an out of bounds memory access and might overwrite important data).