繁体   English   中英

在结构上运行的函数的约定

[英]Conventions for functions that operate on structs

假设我在foo.h具有以下内容:

typedef struct {
    char* my_buf;
    int my_int;
} MyFoo;

/* Creates a foo, allocating memory for my_buf and initializing my_int */
void create_foo(MyFoo *foo);
/* Destroys a foo, freeing the memory for my_buf */
void free_foo(MyFoo *foo);

现在在另一个模块bar.h我有以下内容:

#include "foo.h"

/* Do something with a foo */
void do_something(MyFoo *foo, SomeType_t otherType, ...);

如所写,尚不清楚提供给do_somethingMyFoo是否应使用create_foo进行初始化。 由于它不是const ,我认为应该很清楚地传入foo(即为foo分配的空间),它将以某种方式进行修改,然后用户可以使用修改后的foo。 但是,我如何最有效地指示是否应该“创建”该foo? 一种常见的模式是做类似的事情

MyFoo stackFoo;
do_something(&stackFoo, ...);

但是,如果do_something创建了foo,则用户必须知道他们有责任释放foo。 另一方面,没有办法强制应该创建foo。 我只是在问一个指针(我承认这是一个微不足道的反论点,因为它适用于C语言中的很多东西)。

另一个选择是让MyFoo包含一个“ created”标志,以便该函数可以拒绝尚未创建的任何foo,但这似乎使我过度设计。

我只是想确保我不会错过通用的约定或标准方式来处理此问题。 也许我强迫OOP太多了。 想法和评论表示赞赏!

编辑:有人建议,我同意, create_foo的更好名称是init_foo

是的,您要强制执行 OOP,这没错,但是C中的OOP是有序的。 无论如何,您不能确保尚未在堆栈上创建foo

对于:

void do_something(MyFoo *foo, SomeType_t otherType, ...);

显然,要传递现有的foo ,因为参数是通过值传递的。 因此,语义很明确:必须传递现有的foo

对于:

void create_foo(MyFoo *foo);

由于参数是通过值传递的,这是不对的,这不应该被称为create_foo而应该是init_foo ,或者您应该将参数作为指针的地址传递。 如果是类似OOP的编程,则应区分分配和初始化。

void init_foo(MyFoo *);

MyFoo foo; // simple creation
init_foo(&foo); // initialization

要么

void init_foo(MyFoo *);
MyFoo *alloc_foo();

MyFoo *pfoo = alloc_foo(); // allocation factory
init_foo(pfoo); // initialization
// or with an idiom like
MyFoo *pfoo;
init_foo(pfoo=alloc_foo());

要么:

MyFoo *init_foo(MyFoo *);
MyFoo *alloc_foo();

MyFoo *pfoo = init_foo(alloc_foo());

现在,您还可以调用一个便捷函数:

MyFoo *create_foo(); // alloc+initialization factory
MyFoo *pfoo = create_foo();

或具有传递指针的习惯用法:

void create_foo(MyFoo **f);
MyFoo *pfoo;
create_foo(&pfoo);

如果您希望使用带有模块性的不透明类型,可以更好地控制您的分配,但最终并不能确保用户没有作弊:

// Module foo.c
struct internal_foo {
  int m;
};
void *create_foo() {
  struct internal_foo *pfoo = malloc(...);
  // init structure
  return pfoo;
}
void delete_foo(void *pf) {
  free(pf);
}
// convenient functions for members
void set_m_foo(void *pf,int v) { ((struct internal_foo *)pf)->m = v; }
int get_m_foo(void *pf) { return ((struct internal_foo *)pf)->m; }

因此从外部来看,用户只能看到通用指针。 如果要确保更好的键入,则还可以将通用指针封装到伪结构中: struct MyFoo { void *opaque_foo; } struct MyFoo { void *opaque_foo; }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM