【问题标题】:Why should I declare a C array parameter's size in a function header?为什么要在函数头中声明 C 数组参数的大小?
【发布时间】:2011-03-03 22:08:33
【问题描述】:

谁能告诉我为什么我要费心在函数头中指定 C 数组参数的大小?例如:

void foo (int iz[6]) { iz[42] = 43; }

与:

int is[2] = {1,2,3};

我们得到一个有用的错误。也许它有助于评论/记录?

【问题讨论】:

  • 现在我发现了这个类似的问题:[stackoverflow.com/questions/2374875/… 这主要是一个不确定的评论,尽管 c99 有一些补充。
  • 当你传递一个数组时,它会衰减为一个指向数组第一个元素的指针。所以,数组的大小肯定也应该是接收数组的函数参数。
  • 根据 Dennis Ritchie 的说法,该语法是很久以前试图简化从 B(C 的前身)迁移到 C 的人工制品。最好假装该语法是不允许的,并且永远不要使用它。
  • 开个小玩笑:template void bar(int iz[N]) { iz[N+1] = 44; }

标签: c arrays function-parameter


【解决方案1】:

谁能告诉我为什么我应该费心在函数头中指定 C 数组参数的大小?例如:

void foo (const char sz[6]) { sz[42] = 43; }

IMO,你不应该。当您尝试将数组传递给函数时,真正传递的是指向数组开头的指针。由于函数接收的是一个指针,所以最好把它写成明确的:

void foo(char const *sz)

那么,既然现在很明显该函数没有给出大小的线索,请将其添加为单独的参数:

void foo(char const *sz, size_t size)

【讨论】:

  • 同意。评论用处不大。例如,开发人员可能会修改代码以处理长度为 9 的数组,并意外地将 6 留在原处。
  • @user643722:如果您的问题是开发人员可能会修改代码以使评论不正确,然后无法更新评论,那么您的问题出在每条评论上。这似乎不足以说服人们停止编写它们。
  • “你不应该。”我完全同意。对我来说,以void foo (int iz[6]) 开头的函数隐含地传达(与下一个程序员,而不是编译器)它的实现以某种方式强制执行大小为 6。我们遇到了一些超出其缓冲区的遗留代码的奇怪问题。 myfunc(char buffer[size]) 中的 size 具有欺骗性(或者非 C 编码人员不应该乱搞旧东西)。
  • @Jerry Coffin 您将如何传递一个多维数组并能够将其作为一个数组使用?
【解决方案2】:

这样做的唯一有意义的原因是出于文档目的 - 告诉未来的用户函数期望接收至少有那么多元素的数组。但即便如此,这也是一个约定俗成的问题——您必须事先与其他用户达成一致。语言(编译器)无论如何都会忽略该大小。您的函数声明等效于void foo(int iz[])void foo(int *iz)

使其对编译器有意义的唯一方法是将其声明为

void foo (int iz[static 6])

它向编译器承诺该数组将具有至少 6 个元素,这意味着编译器将能够使用该假设优化该代码。此外,如果你真的想采用上面提到的约定,用static 来声明数组参数大小更有意义,因为语言明确定义了这个结构的语义。

我不清楚你所说的“我们得到一个有用的错误”是什么意思。代码

int is[2] = {1,2,3};
is[42] = 42;

不包含任何约束违规。它会产生未定义的行为,但不需要在编译期间产生诊断消息。换句话说,不,我们没有从中得到任何“有用的错误”。

【讨论】:

  • static 中的 void foo (int iz[static 6]) 是 C99、C11 创新吗?
  • 你能澄清一下什么样的优化吗?
  • @mojuba:例如,生成预取数组数据的机器指令。
  • @chux-ReinstateMonica 在 C99 中添加了 static 的使用
【解决方案3】:

这是一条评论。数组被降级为函数参数中的指针。但是,即使编译器不读取注释,注释仍然有用。

【讨论】:

    【解决方案4】:

    当您想告诉客户端代码它必须传递一个定义大小的数组时,这是一个有用的注释,即:

    void foo(const char bar[5]);
    /* It is expected that foo function receives an array of size 5 */
    

    然而,文档并不能替代代码检查:

    void foo(const char bar[5])
    {
        if (!bar) error();
        if (strlen(bar) != 4) error();
        /* ... */
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-14
      • 1970-01-01
      • 1970-01-01
      • 2011-06-23
      相关资源
      最近更新 更多