我有两个相同类型的对象,例如:
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;
}
但我不知道它的便携性如何(或者可能根本就是错误的)?
我正在寻找最便携的解决方案。
最佳答案
使用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
的则不然,因为对于第二个副本,区域重叠。对于自交换的情况来说,这两种方法都不是最佳选择,但一般来说,这种情况可能非常罕见,因此如果不需要的话,不值得检查指针。
关于c - 如何使用 memcpy 交换两个对象的部分?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5406130/