初始化C语言结构体时的术语

6
这将是一个简单的问题,但是在谷歌上搜索似乎没有提供答案。我理解,在C语言中,当foo是一个结构体时,有两种初始化foo对象的方式。请看下面的代码示例:
typedef struct foo
{
   int var1;
   int var2;
   char* var3;
}foo;

//initializes and allocates a foo
foo* foo_init1(int v1,int v2,const char* v3)
{
   if(..some checks..)
      return 0;
   foo* ret = malloc(sizeof(foo));

   ret->var1 = v1;
   ret->var2 = v2;
   ret-var3 = malloc(strlen(v3)+1);
   strcpy(ret->var3,v3);

   return ret;
}

// initializes foo by ... what? How do we call this method of initialization?
char foo_init2(foo* ret,int v1,int v2, const char* v3)
{
   //do some checks and return false
    if(...some checks..)
         return false//;assume you defined true and false in a header file as 1 and 0 respectively
   ret->var1 = v1;
   ret->var1 = v1;
   ret->var2 = v2;
   ret-var3 = malloc(strlen(v3)+1);
   strcpy(ret->var3,v3);

   return true;
}

因此,我的问题是如何在C语言中引用这些不同的初始化方法?第一个返回一个初始化后的foo指针,因此如果您想要在堆上使用foo对象,那么很容易使用它:
foo* f1 = foo_init1(10,20,"hello");

但第二个需要一个 foo .. 是什么呢?看下面的代码。
foo f1;
foo_init2(&f1,10,20,"hello");

所以第二种方法使得在堆栈上初始化对象变得容易,但是如何调用它呢?这基本上是我的问题,如何引用初始化的第二种方法。
第一种方法分配并初始化了一个指向foo的指针。 第二种方法通过...什么来初始化foo?引用?
作为一个额外的问题,你们在编写C代码时是如何工作的?您确定正在创建的对象的用途,并通过此确定是否应具有type1的初始化函数、type2的初始化函数或两者兼而有之吗?

1
我喜欢将它们称为 _new(用于分配内存)和 _init(不分配内存)。此外,让 _new 在内部调用 _init 可以使您的代码更易于维护。(有时我会使用 _make 代替 _new。) - Chris Lutz
嗨,克里斯,你的观点很好。为什么不把它作为答案发布,这样我就可以投票支持,同时也能让其他有同样问题的 Stack Overflow 用户看到呢? 另外...人们没有一种标准的方式来引用它们吗?我希望查看我的代码(因为它是一个 API)的人可以通过函数名称立即理解不同的用法。 - Lefteris
1
@ChrisLutz:只是为了明确,您会将“_new”、“_init”附加到类型名称上,对吗(例如“foo_new”、“foo_init”)?否则,您将与保留给实现的标识符发生冲突。(我相信您知道这一点;其他人可能不知道。) - Keith Thompson
@ChrisLutz,“new”在C中没有意义,因此不是传达意图的最佳选择。分配和初始化才是你要谈论的内容,而foo_alloc()和foo_init()对于C语言的使用者来说都是易于理解且完全不会引起歧义的。 - tbert
@tbert 想到了同样的事情,因为new是C++的关键字。当然,另一方面,new对于C++程序员来说是立即可识别的,但这是C代码。嗯...有趣的讨论。我现在倾向于使用_init和_alloc。(为什么你们也不将它们作为答案输入,这样我就可以选择接受它们呢?) - Lefteris
显示剩余3条评论
2个回答

1

我不确定这两种方法是否有明确定义的命名法,
在第一种方法中,函数动态分配一个结构并为成员赋值,
而在第二种方法中,结构在函数之前被分配,函数然后只是为成员赋值。

您是否确定正在制作的对象的使用方式,并由此确定是否应该具有类型1或2的初始化函数,甚至两者都有?

选择第一种或第二种方法取决于一个重要的区别:
当您需要跨范围传递返回的结构时,首选第一种方法,堆上的内存必须显式释放,直到数据保留,而在第二种方法中,传递对象的范围结束后,栈上的数据将被删除。


嘿,感谢你的回答。我知道这两种不同方法之间的区别,所以我的问题是,如果说你...需要做你在最后一段中提到的两件事情,你会有两个初始化函数并在适当的时候使用各自的函数吗?另外,由于我不是母语为英语的人,请问你能否给我一个术语来命名第二个函数。这是我提出这个问题的主要原因,因为我想在我的代码库中为函数命名。 - Lefteris

1

由于评论中没有人接受将他们的评论转化为答案的提议,我不得不回复自己的问题。

基本上,可能的答案是,正如AIs所说,没有特定的命名约定。当然,无论使用什么命名方法,都应该:

  • 一致在整个项目中以便清晰明了
  • 可识别被其他程序员视为实际执行其功能的函数。

为了实现这一点,在评论中有一些很好的建议。对于一个foo对象:

  • 传递给函数进行初始化:foo_init
  • 在函数内分配并返回指针:foo_allocfoo_makefoo_new

我想以上所有的方法都很清楚,但最准确地描述函数中正在发生的事情的是foo_initfoo_alloc

就我个人而言,我真的不喜欢_alloc解决方案,因为我不喜欢它在我的代码中的外观,所以我决定在函数后添加动词_create来表示它正在做什么。

但是,我想归根结底,答案取决于个人喜好。只要通过阅读函数的名称清晰地了解其功能,所有写法都应该是可以的和可接受的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接