I have two objects both of the same type, for instance:
typedef struct s_Object
{
signed int a[3];
double float b;
unsigned short int c[30];
struct s_Object *next,
*prev;
} t_Object;
t_Object A, B;
I need some generic function like:
swap_vars(&A, &B);
which will not swap pointers but all other data the objects can contain. Is it possible in C?
Assuming pointers are placed in the highest addresses, my first idea was:
void swap_vars(t_Object *pA, t_Object *pB){
t_Object C;
memcpy(&C, pA, sizeof(t_Object)-sizeof(t_Object *)*2;
memcpy(pA, pB, sizeof(t_Object)-sizeof(t_Object *)*2;
memcpy(pB, &C, sizeof(t_Object)-sizeof(t_Object *)*2;
}
but I don’t know how portable is it (or maybe wrong at all)?
I am looking for a most portable solution.
Use
offsetof:The reason is that
t_Objectmight have padding at the end, so if you copy all but the last 8 bytes, you might be copying part or all of the pointers.I’m not sure whether this is strictly conforming – the standard says you can copy a whole object, but I’m not sure what it says about parts of objects.
It would be a bit strange, but imagine that this struct had some padding in the middle, and some at the end, and the implementation filled all the padding in each object with the same byte value, chosen at random, and later checked to see that the padding was still consistent. I don’t think that’s forbidden. Then this wouldn’t work.
In practice, though, this is pretty portable. In particular, members have to appear in the order they’re defined, so
offsetof(t_Object, next)certainly captures the part of the object up to (but not including) the pointers.If you’re able to change the structure, then you could build it up from a swapped part, and an unswapped part:
Swap is then:
Edit: prompted by memcpy vs assignment in C — should be memmove?
This latter also has the advantage that it’s guaranteed by the standard to work when
pA == pB. The one withmemcpyisn’t, because for the second copy the regions overlap. Neither is optimal for the case of a self-swap, but generally speaking those are probably so rare that it isn’t worth checking the pointers if you don’t have to.