如何设计用ANSIC编写的库?

如何设计用ANSIC编写的库?,c,malloc,C,Malloc,我想用ANSIC开发一个库 我有一个字符串结构: struct libme_string { char* buffer; int length; }; 我想写一个函数,libme\u create\u string(),它创建并初始化一个字符串(类似于C++中的构造函数) 以下哪种方法更适合设计libme\u create\u string() 方法#1 为libme\u create\u string()中的字符串对象分配内存并返回: struct libme_string* li

我想用ANSIC开发一个库

我有一个
字符串
结构

struct libme_string
{
  char* buffer;
  int length;
};
我想写一个函数,
libme\u create\u string()
,它创建并初始化一个
字符串(类似于C++中的构造函数)

以下哪种方法更适合设计
libme\u create\u string()


方法#1 为
libme\u create\u string()
中的字符串对象分配内存并返回:

struct libme_string* libme_create_string(int length)
{
  // Check arguments...

  // Allocate memory for object.
  struct libme_string* str = malloc(sizeof(struct libme_string));

  // Handle memory allocation errors...

  str->buffer = malloc(length);
  str->length = length;

  // Handle memory allocation errors...

  return str;
}

void libme_delete_string(struct libme_string* str)
{
    // Check arguments...

    free(str->buffer);
    free(str);
}
使用
方法#2 不要为
libme\u create\u string()函数中的字符串对象分配内存,请将其作为参数接受:

struct void libme_create_string(libme_string* str, int length)
{
  // Check arguments...

  // Just allocate memory for members.
  str->buffer = malloc(length);
  str->length = length;

  // Handle memory allocation errors...
}

void libme_delete_string(struct libme_string* str)
{
  // Check arguments...

  free(str->buffer);
}
使用
struct libme_string str;// 就个人而言,我认为第二个版本不那么直观,更容易出错


如果您正在尽最大努力封装实例化(无论如何,您都应该这样做),那么第一步确实是唯一的方法——一步,完成。第二个版本意味着,为了拥有一个完全初始化的变量,您不仅需要实例化它,还需要立即对其调用一个helper函数。这个额外的步骤是一个等待发生的错误。

为什么不将这个过程分成两个函数,这样您就可以使用您需要的任何函数:

struct libme_string * create_string();
void destroy_string(struct libme_string *);

struct libme_string * init_string(struct libme_string * str, unsigned int length);
struct limbe_string * deinit_string(struct libme_string * str);
用法#1,所有动态分配:

struct libme_string * str = init_string(create_string(), 10);
destroy_string(deinit_string(str));
用法#2,自动外部结构:

struct libme_string str;
init_string(&str);
deinit_string(&str);
确保init函数返回指针,这样您就可以像我一样编写调用了


如果
deinit()
也将指针设置为零,那么如果指针为非零,则可以调用
destroy()
调用
deinit()
,尽管这会稍微破坏对称性。

我个人更喜欢第一种方法。同意:这有点像C++,但是……
thing_t *thing_new(...);
void thing_delete(thing_t *ptr);
我确实认为所有“size”或“count”成员都应该是无签名的,最好是size\t。 另外:最后一个代码段尝试释放()一个自动变量。这是不使用它的一个很好的理由

编辑:

有(至少)第三种方法:将整个对象作为值返回。我并不特别喜欢这种方法,但它至少避免了双重分配。事情是这样的:

typedef struct {
  StrLen length;
  StrType type;      /* type is not stored in the brainfile 
                     **but recomputed on   loading */
  char *word;
} STRING;

STATIC STRING new_string(char *str, size_t len)
{
STRING this;

if (str) {
     if (!len) len = strlen(str);
     if (len) { this.word = malloc(len); memcpy(this.word, str, len); }
     else { this.word = malloc(1); memset(this.word, 0, 1); }
     this.length = len;
     this.type = word_classify(this);
     }
else        {
     this.word = NULL;
     this.length = 0;
     this.type = 0;
     }
return this;
}
if (*np == WORD_NIL) {
  STRING this;
  *np = dict->size++;
  this = new_string(word.word, word.length);
  dict->entry[*np].string = this;
  dict->entry[*np].hash = hash_word(this);
  }
典型用法如下:

typedef struct {
  StrLen length;
  StrType type;      /* type is not stored in the brainfile 
                     **but recomputed on   loading */
  char *word;
} STRING;

STATIC STRING new_string(char *str, size_t len)
{
STRING this;

if (str) {
     if (!len) len = strlen(str);
     if (len) { this.word = malloc(len); memcpy(this.word, str, len); }
     else { this.word = malloc(1); memset(this.word, 0, 1); }
     this.length = len;
     this.type = word_classify(this);
     }
else        {
     this.word = NULL;
     this.length = 0;
     this.type = 0;
     }
return this;
}
if (*np == WORD_NIL) {
  STRING this;
  *np = dict->size++;
  this = new_string(word.word, word.length);
  dict->entry[*np].string = this;
  dict->entry[*np].hash = hash_word(this);
  }
(代码继承自megahal,在wakkerbot中重用)
正如我所说的,我不喜欢这种方法,但是结构赋值肯定有它的优点。

当我
init_string
,做一些事情,忘记如何实例化对象,然后调用
destroy_string
?我认为这种方法很容易出错。如果你忘了编写正确的代码,那么C有很多很多诀窍让你绞尽脑汁:-)你可以为动态分配创建一个函数来完成所有事情,另外一个函数只用于内部初始化,如果这更有用的话。或者使用C++ +:-版本2比版本1的内存分配慢?基本上是分配相同数量的内存。您的某些更改被我意外还原。另一个选项是在创建函数中返回结构(而不是指向它的指针)。@Vaughn:但当sizeof(struct X)是一个大数字时,这不是一个好主意。我想您会发现返回结构的速度与方法#2一样快。通过将指针传递到被调用函数中返回结构。使用优化编译时,副本也会被省略。您上一个代码段尝试释放()一个自动变量。谢谢我纠正它:)