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

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

但我不知道它的便携性如何(或者可能根本就是错误的)?

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

最佳答案

使用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/

相关文章:

C - 匿名结构有什么优势?

c - sizeof 的功能

c - 如何创建动态大小的 NULL 指针数组?

c - 关于C指针的两个问题

python - 将带有 M 和 K 的字符串对象值转换为百万和千

javascript - 更改 <object> 高度和宽度在 Chrome 中有效,但在 Firefox 或 IE 中无效。为什么?

c - C-使用read()和write()从一个文件复制到另一个文件,而不使用文件功能

c - ndisasm手册中提到的二进制文件和可执行文件有什么区别?

复制指针字符未按预期工作

c# - 有没有简单的方法来检查任何类实例的修改?