Use offsetof
:
memcpy(&C, pA, offsetof(t_Object, next));
The reason is that t_Object
might 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:
typedef struct payload {
signed int a[3];
double float b;
unsigned short int c[30];
} payload;
typedef struct s_Object {
payload data;
struct s_Object *next, *prev;
} t_Object;
Swap is then:
payload C = pA->data;
pA->data = pB->data;
pB->data = C;
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 with memcpy
isn'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.