2011-03-23 26 views
2

我有两个对象都同一类型的,例如:如何使用memcpy交换两个对象的部分?

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

你不应该假设任何关于结构的布局,只是使用他们的名字memcopy个别成员 – 2011-03-23 13:46:38

+0

@Martin:这不是一个漂亮的解决方案,因为每次我将改变对象的类型描述,我必须更新这个函数以及。 – psihodelia 2011-03-23 13:50:51

回答

3

使用offsetof

memcpy(&C, pA, offsetof(t_Object, next)); 

的原因是t_Object可能在年底有填充,因此,如果您复制所有,但最后8个字节,你可能会复制部分或全部指针。

我不确定这是否严格符合 - 标准说你可以复制整个对象,但我不确定它对部分对象的说法。

这会有点奇怪,但想象一下,这个结构在中间有一些填充,有些在最后,实现用随机选择的相同字节值填充每个对象中的所有填充,然后稍后检查以查看填充是否一致。我不认为认为这是禁止的。那么这是行不通的。

实际上,这是非常便携的。特别是,成员必须按照他们定义的顺序出现,所以offsetof(t_Object, next)肯定会捕获对象的部分(但不包括)指针。

如果你能够改变结构,那么你可以从一个交换部分建立起来,并且unswapped部分:

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

+0

谢谢,使用有效载荷的好主意!看起来我已经在某处看到过类似的东西(无论是git还是python源代码)。 – psihodelia 2011-03-23 14:06:02