【问题标题】:Passing a struct to a function in C将结构传递给C中的函数
【发布时间】:2013-04-12 05:12:07
【问题描述】:

如果我有以下情况:-

struct foo
{
  int a;
  int *b;
} bar;

void baz(struct foo qux)
{

}

我是否认为将bar 传递给baz() 会导致bar 的本地副本被推入堆栈?如果是这样,这是什么副本?在 C++ 中,我假设它会调用复制构造函数或默认的复制构造函数,但我真的不知道这在 C 中是如何工作的。

C 是否有任何默认复制构造函数的概念,它有名称吗?可以做些什么来执行深层复制吗? (假设)。我能想到的唯一方法是实际进行深层复制,然后将其传递给函数。

通常,我会传递一个指向foo 的指针,但我只是好奇它是如何工作的。此外,我的印象是传递指针更快,节省内存,并且是执行此类操作时推荐的操作过程。我猜这是一个浅拷贝;这个可以改吗?

【问题讨论】:

    标签: c


    【解决方案1】:

    我是否认为将 bar 传递给 baz() 会导致 bar 的本地副本被推入堆栈?

    是的。

    我真的不知道这在 C 中是如何工作的。

    基本上与 C++ 中的默认复制构造函数一样;副本的每个字段都使用原始字段的相应字段进行初始化。当然,由于“好像”规则,整个事情可能归结为memcpy

    我的印象是传递指针更快,节省内存,并且是执行此类操作时推荐的操作过程。

    对于较大的structs,通常是这种情况,但并不总是这样;如果你有一个小的 struct 几个小字段,则复制的开销可能会小于间接的开销(此外,使用指针参数可能会很昂贵,因为 C 和 C++ 的别名规则会阻止一些优化)。

    我猜这是一个浅拷贝;这个可以改吗?

    不,浅复制(盲目复制每个字段)是默认复制构造函数所发生的(而“深度复制”通常意味着创建指针/引用字段中引用的每个对象的副本)。

    您的意思是“通过引用传递”,它不是默认允许最大灵活性(以及与原始类型传递的一致性)。如果你想通过引用传递,你传递一个指针(或 C++ 中的一个引用),如果你只是为了性能,通常是 const,否则你传递对象本身。

    【讨论】:

    • 附注C 中本身没有构造函数;仅在 C++ 中。在 C 中,您的数据结构将简单地逐字节复制。
    • @EdwardFalk:当然,实际上我说的是初始化,而不是构造;此外,标准没有指定“逐字节”的事情,它实际上说只有命名字段保证被复制(“结构对象的未命名成员即使在初始化后也具有不确定的值。”,C99 §6.7 .8 ¶9) - 即,可以复制也可以不复制填充。
    • 很好的解释,我猜如果需要,您不能覆盖默认行为来执行深层复制?
    • @chrisw69:您可以在 C++ 中提供您的自定义复制构造函数;它是例行的,例如在标准库容器中(std::vector,...)。相反,在 C 中,没有自动机制,您必须提供自己的函数(手动调用)来执行深层复制。顺便说一句,这被某些人视为一个优势,因为某些对象的“默认深拷贝”策略如果没有很好地理解,可能会导致相当大的减速。与 Java 或 C# 相比,其中对象默认通过引用传递,但可以选择提供 Clone 方法来执行深层复制。
    • 我相信C#和java,对象引用是按值传递的; ref 关键字通过引用传递对象,据我所知,这与将指针传递给 C 或 C++ 等语言中的指针是相同的。就 Clone 而言,我认为不推荐使用 ICloneable 接口,因为它没有指定克隆是深还是浅。 stackoverflow.com/questions/536349/why-no-icloneablet
    【解决方案2】:

    是的,将 bar 的本地副本推入堆栈。其余的将在以下工作示例中进行评论。

        #include <stdio.h>
        struct foo
        {
            int a;
            int *b;
        } bar;
        void baz(struct foo qux)
        {
            bar.a = 2; // if its a different copy then printf on main should print 1 not 2.
            *bar.b = 5; // if its a different copy then printf on main should print 5 not 4. since the place pointer pointing to is same
        }
        int main(){
            bar.a=1;
            bar.b = (int*)malloc(sizeof(int));
            *bar.b = 4;
            baz(bar); // pass it to baz(). now the copy of bar in the stack which is what baz going to use
            printf("a:%d | b:%d\n",bar.a,*bar.b);
            //answer is  2 and 5
            /*So indeed it does a shallow copy thats why we lost the "4" stored in bar.b it did not created new space in heap to store "5" instead it used the same space that b was pointing to.
            */
        return 0;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-03
      • 1970-01-01
      • 1970-01-01
      • 2018-05-29
      相关资源
      最近更新 更多