【问题标题】:Is it good practice to copy objects from the stack to the heap by setting a dereferenced pointer?通过设置取消引用的指针将对象从堆栈复制到堆是一种好习惯吗?
【发布时间】:2020-07-13 13:55:51
【问题描述】:

请考虑这个示例程序:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
  int a;
  int b;
} X;

int main(void) {
  X* p = malloc(sizeof(X)); // Heap allocation
  X z = {.a = 2, .b = 3}; // Stack allocation
  *p = z; // Copying from the stack onto the heap

  printf("\n%d\n", p->b);

  return 0;
}

此程序正确打印3。我假设这意味着*p = z 成功地将z 的数据从堆栈复制到了堆中。

如果可以很容易地将堆栈中的内容复制到堆中,为什么大多数人在尝试这样做时使用memcpy(E.g. this SO question).

memcpy 在什么情况下合适,而上述解决方案在什么情况下合适?

【问题讨论】:

  • 这是一个有效的代码。您可以将结构的一个对象分配给正常结构的另一个对象。 memcpy 用于例如没有结构对象或您需要进行“深度”复制时。
  • assignment和memcpy之间的选择只是个人风格,没有什么重要的原因。
  • 但是如果是数组而不是单个对象,则需要使用memcpy,因为不能分配数组。
  • @VladfromMoscow memcpy() 不做深拷贝。它只是复制顶级对象的字节。
  • @VladfromMoscow 赋值和 memcpy 都会以同样的方式复制指针。 memcpy() 不会递归。

标签: c stack heap-memory


【解决方案1】:

“通过设置取消引用的指针将对象从堆栈复制到堆中是一种好习惯吗?”

是的。 *p = z; 很好。优于memcpy():类型检查。

memcpy 在什么情况下合适,而上述解决方案在什么情况下合适?

  • memcpy: 复制数组时

  • memcpy:当源/目标不对齐时(代码需要打包/解包数据)。

  • 否则:使用简单的赋值。

【讨论】:

    【解决方案2】:

    当您将一个数组的内容复制到另一个数组时(并且这些内容不构成 字符串),或者当您尝试映射将一种类型的对象复制到另一种类型的对象的字节上。

    例如,如果您将struct 类型映射到unsigned char 数组,您可以执行以下操作:

    X foo = {1, 2};
    unsigned char *bytes = malloc( sizeof foo );
    unsigned char sbytes[sizeof foo];
    
    memcpy( bytes, &foo, sizeof foo );
    memcpy( sbytes, &foo, sizeof foo );
    

    同样,如果您尝试将一个数组的内容复制到另一个数组并且这些内容不构成 字符串,您也可以使用 memcpy:

    int src[N];
    int *dst = malloc( sizeof src );
    int sdst[N];
    ...
    memcpy( dst, src, sizeof src );
    memcpy( sdst, src, sizeof src );
    

    如果它们确实构成了一个字符串,你会使用strcpy

    char blah[10];
    strcpy( blah, "foo" );
    

    否则,请使用您在此处所做的赋值运算符。

    【讨论】:

    • 这两个选项computionally是否相同?我可以说,在嵌入式环境中,直接分配真的很少见(至少可以这么说)。
    • @RobertoCaboni:我没有嵌入式系统可以方便地使用。我刚刚做了一个简单的测试,它使用memcpy 和直接赋值来复制带有两个int 成员的struct 类型,gcc 为两者生成了相同的代码 - 它用一个替换了memcpy 调用直接赋值(这是有道理的,因为在这种情况下两个操作数都是相同的类型)。
    • 嗨,约翰,感谢您的帮助。两个问题: 1. 很确定我知道这一点,但可以公平地说,memcpystrcpy 之间的唯一区别是后者不需要指定大小来复制,而是在第一个遇到 NULL 字节时终止.正确的? 2. "...将一种类型的对象的内容映射到另一种类型的对象的字节上..." - 有趣,你能举个例子吗?我不清楚。谢谢!
    • @AvivCohn: 1. 对 - strcpy 用于在字符类型的数组之间复制字符串 - 它是 memcpy 的特例。 2. 看我的第一个例子,我将foo 的字节映射到unsigned char 的数组上。作为另一个示例,您可以将 float 的字节复制到 long - strcpy( &amp;long_object, &amp;float_object, sizeof long_object); - 这会在 float 对象中保留 float 对象的位模式@ 对象(直接赋值会将 floatlong表示 - 即3.0 => 3)
    • 只是出于好奇,关于将 float 的复制位模式复制到 long 示例中,您能否举一个您需要执行此类操作的真实场景示例?
    猜你喜欢
    • 1970-01-01
    • 2011-08-30
    • 1970-01-01
    • 1970-01-01
    • 2011-03-22
    • 1970-01-01
    • 2019-11-20
    • 2011-01-28
    • 2018-08-25
    相关资源
    最近更新 更多