编码风格 - 通过参考或通过价值?

时间:2014-12-27 07:45:24

标签: c styles pass-by-reference pass-by-value

为了简化未来学校作业的开发,我决定为我常用的两个数据结构创建一个API(这就是你所说的吗?) - 一个链表和一个哈希表。

在开发这些中的每一个时,我最终得到了以下两个插入函数:

int list_insert(list *l, char *data, unsigned int idx);
int hash_insert(hash_table **ht, char *data);

list_insert()函数(以及所有列表函数)最终都是按值传递,因为我从来没有必要直接修改list *本身,除非我是malloc'或免费的。但是,因为我想在我的哈希表中包含自动重写,我发现我必须在任何可能强制重新哈希的函数中通过引用而不是by-value传递表。现在我最终得到如下语法:

list_insert(l, "foo", 3);
hash_insert(&ht, "foo");

差别让​​我觉得有些奇怪,我发现自己想知道是否应该将列表功能更改为传递引用以及一致性 - 即使我的功能都不需要利用它。这里的典型共识是什么?如果我的函数实际上需要修改它的参数,或者为了保持一致性而应该通过引用传递,我应该只通过引用传递吗?

结构定义:

typedef struct list_node list_node;
struct list_node {
    char *data;
    list_node *next;
    list_node *prev;
};

typedef struct list list;
struct list {
    list_node *head;
    list_node *tail;
    size_t size;
};

typedef struct hash_table hash_table;
struct hash_table {
    list **table;
    size_t entries;
    size_t buckets;
    float maxLoad;
    unsigned int (*hash)(char*, unsigned int);
};

列表功能:

list *list_createList();
list_node *list_createNode();
void list_destroyList(list *l);
void list_destroyNode(list_node *n);
int list_append(list *l, char *data);
int list_insert(list *l, char *data, unsigned int idx);
int list_remove(list *l, char *data, int (*compar)(const void*, const void*));
void list_push(list *l, char *data);
char *list_pop(list *l);
int list_count(list *l, char *data, int (*compar)(const void*, const void*));
int list_reverse(list *l);
int list_sort(list *l, int (*compar)(const void*, const void*));
int list_print(list *l, void (*print)(char *data));

哈希函数:

hash_table *hash_createTable(size_t buckets, float maxLoad, unsigned int (*hash)(char*, unsigned int));
void hash_destroyTable(hash_table *ht);
list *hash_list(const hash_table **ht);
int hash_checkLoad(hash_table **ht);
int hash_rehash(hash_table **ht);
int hash_insert(hash_table **ht, char *data);
void hash_stats(hash_table *ht);
int hash_print(hash_table *ht, void (*print)(char*));

2 个答案:

答案 0 :(得分:1)

这取决于你并采取一点直觉。当传递大型结构时,我通过引用传递,这样我就不会占用额外的堆栈空间并且烧掉循环复制结构。但是对于像你这样的小型struts,使用堆栈可能会更有效,具体取决于你的目标处理器,你使用这些值的频率,以及编译器的作用。您的编译器可能会破坏该结构并将其值放入寄存器中。

但是如果您通过引用传递并且不打算修改值,则最好将指针传递给const,例如:const list * l。这样就不会有意外修改值的风险,它会使界面更清晰 - 现在调用者知道值不会改变。

一致性很好,我个人会倾向于这个方向,特别是在大型界面上,因为从长远来看它可能会让事情变得更容易,但我肯定会使用const。在这样做时,您允许编译器发现任何意外分配,以便以后您不需要追踪难以发现的错误。

另请参阅:Passing a struct to a function in C

答案 1 :(得分:1)

以下是一般的经验法则:

  • 如果其typdef是本机类型(char,short,int,long,long long,double或float),则按值传递
  • 通过引用传递,如果它是union,struct或array

通过引用传递的其他注意事项:

  • 如果不修改则使用const
  • 如果指针不指向同一地址,则使用restrict

有时,struct / union 似乎类似于适当的类型,但如果类型相似,则可以用数组替换。这有助于优化(例如循环矢量化)