Rich Jahn Rich Jahn - 4 months ago 6
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).

Comments