jayjay jayjay - 1 month ago 18
C Question

Converting to non-scalar type

I have 2 structs of the same size, layout and alignment, but of different types. I would like to copy one onto the other.

struct one s1;
struct two s2;

...

s1 = (struct one)s2; // error: conversion to non-scalar type requested
s1 = *((struct one*)&s2); // fine?


Is the 2nd method safe & portable?

Bonus: What was the thinking of the language designers here, are they making sure I take off the safety before I shoot myself in the foot?

Answer

2nd method is portable as updated.

Converting object pointers types to void* and back to original is fine. Between other pointer types may be UB. The trick is that even though the one and two are the same size, we do not know they have the same alignment requirements which may differ because of their unposted members.

A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer. C11dr §6.3.2.3 1

A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. §6.3.2.3 7

OP details that "layout" (now "aliment") implies matching alignment (of all fields). If that is the case, then s1 = *((struct one*)&s2); is acceptable.

For unquestionable portability, use memcpy()/memmove() or consider a union.

assert(sizeof s1 == sizeof s2);
memcpy(&s1, &s2, sizeof s1);

What was the thinking of the language designers here, are they making sure I take off the safety before I shoot myself in the foot?

By coding s1 = *((struct one*)&s2);, you tell the compiler, "don't worry about the cast, I know what I am doing."

C was designed to be used by knowledgeable programmers to craft tight code who know when to cheat.

C is coding without a net
image at https://sparkfun.com.