【问题标题】:Can I use arrays as a function parameter in C99?我可以在 C99 中使用数组作为函数参数吗?
【发布时间】:2013-09-20 21:46:35
【问题描述】:

C99 标准在 6.7.5.3/7 中说明如下:

将参数声明为“类型数组”应调整为“限定指针” type'',其中类型限定符(如果有)是在 [ 和 ] 中指定的那些 数组类型推导。

我理解为:

void foo(int * arr) {} // valid
void foo(int arr[]) {} // invalid

但是,gcc 4.7.3 将愉快地接受这两个函数定义,即使使用gcc -Wall -Werror -std=c99 -pedantic-errors 编译也是如此。由于我不是 C 专家,我不确定我是否误解了标准的含义。

我也注意到了

size_t foo(int arr[]) { return sizeof(arr); }

将始终返回 sizeof(int *) 而不是数组大小,这坚定了我的信念,即 int arr[] 被处理为 int * 而 gcc 只是想让我感觉更舒服。

有人能解释一下这个问题吗?仅供参考,这个问题来自this comment

【问题讨论】:

  • 编译器正在执行 C99 标准引用所说的:它将 [] 形式调整为 * 形式。因此两者是等价的。 (几乎)没有办法将整个数组按值传递给 C 函数。您只能传递一个指针并在函数体内手动复制。例外的是,记录中的数组字段在传值时会随记录一起传值。因此,有时您会看到一个数组字段的记录,其中记录只是包装数组以获得这种效果。
  • @Gene D'uh,我错误地将该标准段落作为对 C 程序员而非 C 编译器的指令阅读。愚蠢的我。

标签: c arrays c99


【解决方案1】:

您的 validinvalid 声明在内部都是等效的,即编译器将后者转换为前者。

你的函数看到的是指向数组第一个元素的指针。

附言。另一种方法是将整个数组压入堆栈,从时间和空间的角度来看,这将是非常低效的。

【讨论】:

    【解决方案2】:

    一些上下文:

    首先,请记住,当“T 的 N 元素数组”类型的表达式出现在它不是 sizeof 或一元 & 运算符的操作数的上下文中时,或者不是t 用于在声明中初始化另一个数组的字符串文字,它将被转换为类型为“指向T”的表达式,其值将是数组中第一个元素的地址。

    这意味着当您将数组参数传递给函数时,该函数将接收一个指针值作为参数;在调用函数之前,数组表达式被转换为指针类型。

    这一切都很好,但为什么arr[] 允许作为指针声明?我不能说这是肯定的原因,但我怀疑这是从 B 语言中继承下来的,C 是从 B 语言中派生出来的。事实上,几乎所有关于 C 中数组的奇怪或不直观的东西都是 B 的保留。

    B 是一种“无类型”语言;对于浮点数、整数、文本等,您没有不同的类型。一切都存储为固定大小的单词或“单元”,而内存被视为单元的线性阵列。当你在 B 中声明一个数组时,如

    auto arr[10];
    

    编译器会为数组留出 10 个单元格,然后留出额外的第 11 个单元格来存储数组第一个元素的偏移量,并且该额外的单元格将绑定到变量 arr。与 C 中一样,B 中的数组索引计算为*(arr + i);您将获取存储在arr 中的值,添加偏移量i,然后取消引用结果。 Ritchie 保留了大部分这些语义,除了不再为指向数组第一个元素的指针留出存储空间。相反,当代码被翻译时,该指针值将从数组表达式本身计算。这就是为什么数组表达式被转换为指针类型,为什么&arrarr 给出相同的值,如果不同的类型(数组的地址和数组的第一个元素的地址相同)以及为什么数组表达式不能是赋值的目标(没有什么可以赋值;没有为独立于数组元素的变量预留存储空间)。

    现在有趣的部分来了;在 B 中,您将“指针”声明为

    auto ptr[];
    

    这具有分配单元格以存储数组第一个元素的偏移量并将其绑定到ptr 的效果,但ptr 并没有特别指向任何地方;您可以将其分配为指向不同的位置。我怀疑符号被搁置有几个原因:

    1. 大多数从事 C 初始版本工作的人都熟悉它;
    2. 有点强调参数代表调用者中的一个数组;

    就个人而言,我更希望 Ritchie 使用* 来指定任何地方的指针,但他没有(或者,或者,使用[] 来指定所有上下文中的指针,而不仅仅是函数参数声明) .我通常会建议大家对函数参数使用* 表示法而不是[],因为它更准确地传达了参数的类型,但我可以理解为什么人们更喜欢第二种表示法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-25
      • 1970-01-01
      • 2015-03-10
      • 1970-01-01
      • 2020-11-29
      • 1970-01-01
      • 2019-10-18
      • 2011-01-25
      相关资源
      最近更新 更多