我有两个相同类型的对象,例如:
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;
我需要一些通用函数,如:
swap_vars(&A, &B);
不交换指针,但是对象可以包含的所有其他数据。是否有可能在C?
假设指针放在最高地址,我的第一个想法是:
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;
}
但我不知道它是多么便携(或者可能是错误的)?
我正在寻找最便携的解决方案。
答案 0 :(得分:3)
使用offsetof
:
memcpy(&C, pA, offsetof(t_Object, next));
原因是t_Object
最后可能有填充,所以如果你复制除了最后8个字节以外的所有字符,你可能会复制部分或全部指针。
我不确定这是否严格符合 - 标准说您可以复制整个对象,但我不确定它对部分对象的说法。
这有点奇怪,但是想象一下这个结构在中间有一些填充,有些在最后,并且实现填充了每个对象中的所有填充,具有相同的字节值,随机选择,以后检查填充是否仍然一致。我不认为是禁止的。然后这不起作用。
但实际上,这是非常便携的。特别是,成员必须按照它们定义的顺序出现,因此offsetof(t_Object, next)
肯定会捕获对象的一部分(但不包括)指针。
如果你能够改变结构,那么你可以从一个交换的部分和一个未被破坏的部分构建它:
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;
然后交换:
payload C = pA->data;
pA->data = pB->data;
pB->data = C;
编辑:memcpy vs assignment in C -- should be memmove?提示
后者的优点还在于pA == pB
时标准可以保证工作。 memcpy
的那个不是,因为对于第二个副本,区域重叠。对于自交换的情况来说,这两者都不是最佳的,但一般来说,这些可能是非常罕见的,如果你不需要检查指针是不值得的。