C函数参数:struct或const struct *

时间:2014-09-27 12:09:15

标签: c pointers struct arguments prototype

目标是帮助其他程序员编写可读性。

在创建函数原型时,我倾向于将简单类型(int,char)直接放入原型中,而更复杂的结构通常作为指针传递(struct complex *)。

当然,这通常是#34;并且有一些明显的反例:如果函数必须修改一个简单的参数,则将指针传递给它。

但是现在,假设在我的函数参数中,我得到一个复杂但不那么庞大的结构,在只读模式下传递(它不会被修改)。到目前为止,我会做这样的事情:

int myFunction1(int var1, const complexStruct* var2Ptr);

当然可行。但是现在,我想知道,因为结构的内容无论如何都不会被修改,而是定义这样的函数原型会更好:

int myFunction2(int var1, complexStruct var2);

很难说。我的胆量告诉我myFunction2可能更容易阅读,因此使用,特别是新手程序员,往往不喜欢指针。经验丰富的程序员可能不会介意。

我还猜测,作为参数列表的一部分复制到堆栈的数据量对于myFunction2来说会更高(假设myFunction2不会被编译器自动内联)。当然,只要complexStruct不是太大,它就不应该成为问题。但这意味着结构的大小是决定因素。

最后,我想myFunction2可能更容易由编译器内联。但那只是一个疯狂的猜测。

无论如何,由于两个函数原型看起来都是等价的,我对于哪个函数原型可能更为可能有点无能为力,并且想知道是否还有其他考虑因素,可能更重要的是要考虑决策。

到目前为止收到的评论摘要:

简而言之,在大多数情况下更喜欢const struct *。

1 个答案:

答案 0 :(得分:1)

特别是对于“属于”某种数据类型的函数,我更喜欢将指针作为第一个参数传递(如C ++中的this指针)。它还使变异和非变异函数的签名更加一致。

考虑使用struct stackstack_push(变异)和(非变异)stack_pop函数的stack_top。类型可能小到

struct stack
{
  size_t capacity_;
  size_t size_;
  char * data_;
};

所以我们不应该担心复制几个字。 (它实际上可能比取消引用非本地指针更快。)

不过,我发现这套“会员功能”

extern int stack_init(struct stack * this);
extern int stack_deinit(struct stack * this);
extern int stack_push(struct stack * this, char value);
extern int stack_pop(struct stack * this);
extern int stack_top(const struct stack * this);
extern int stack_size(const struct stack * this);

void
usage_example()
{
  struct stack mystack;
  if (stack_init(&mystack) < 0) { /* handle error */ }
  if (stack_push(&mystack, 'a') < 0) { /* handle error */ }
  assert(stack_top(&mystack) == 'a');
  assert(stack_size(&mystack) == 1);
  stack_deinit(&mystack);
}

比这个更加一致:

extern int stack_init(struct stack * this);
extern int stack_deinit(struct stack * this);
extern int stack_push(struct stack * this, char value);
extern int stack_pop(struct stack * this);
/* Duckling asks: What is the difference between 'this' and 'self'? */
extern int stack_top(struct stack self);
extern int stack_size(struct stack self);

void
usage_example()
{
  struct stack mystack;
  if (stack_init(&mystack) < 0) { /* handle error */ }
  if (stack_push(&mystack, 'a') < 0) { /* handle error */ }
  /* Duckling asks: Are you sure you didn't forget the '&' here? */
  assert(stack_top(mystack) == 'a');
  assert(stack_size(mystack) == 1);
  stack_deinit(&mystack);
}

如果可能的话,我认为某些东西是const的事实应该是编译器的关注,而不是强迫程序员使用另一个调用约定。

这与问题无关,但万一有人问:stack_topstack_pop函数的返回值是相应的字符,或者是下溢的-1。其他函数在成功时返回0,在错误时返回负错误代码(例如内存不足)。