如何使用memcpy交换两个对象的部分?

时间:2011-03-23 13:42:59

标签: c pointers object memory-management

我有两个相同类型的对象,例如:

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;
}

但我不知道它是多么便携(或者可能是错误的)?

我正在寻找最便携的解决方案。

1 个答案:

答案 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的那个不是,因为对于第二个副本,区域重叠。对于自交换的情况来说,这两者都不是最佳的,但一般来说,这些可能是非常罕见的,如果你不需要检查指针是不值得的。