C 函数:数组参数长度

use*_*536 3 c arrays language-lawyer implicit-conversion function-declaration

这个问题建立在这个问题的基础上,它描述了以下内容如何等效:

int f(int a[10]) { ... } // the 10 makes no difference
int f(int a[]) { ... }
int f(int *a) { ... } 
Run Code Online (Sandbox Code Playgroud)

在有关函数原型作用域的文档中,提供了以下示例:

int f(int n, int a[n]); // n is in scope, refers to first param
Run Code Online (Sandbox Code Playgroud)

这让我质疑以下内容在多大程度上是等效的:

// 1.
int f(int n, int a[n]) { ... }
int f(int n, int *a) { ... }
// my guess: exactly equivalent

// 2.
int x = 10; int f(int a[x]) { ... }
int x = 10; int f(int *a) { ... }
// my guess: exactly equivalent

// 3.
int f(int a[n], int n) { ... }
int f(int *a, int n) { ... }
// my guess: not equivalent: first f won't compile, second will
Run Code Online (Sandbox Code Playgroud)

结论问题:

  • 假设两者都可以编译,int f(int arr[n])并且int f(int *arr)总是等效吗?
  • 为什么编译器要查找标识符n,即使它的值不会被使用。
    • 我的猜测:将 包含在源代码中的唯一原因n是作为文档来指示数组应具有的最小长度。确保其n在范围内并且具有正确的类型,确保本文档有意义

Eri*_*hil 9

假设两者都可以编译,int f(int arr[n])并且int f(int *arr)总是等效吗?

不,C 标准在这一点上是有缺陷的;它没有说明nin是否int arr[n]被评估。

int arr[n]名义上声明一个可变长度数组(假设n是某个对象的标识符,而不是常量的宏)。C 标准规定会评估可变长度数组的大小,并且还规定参数声明int arr[n]会自动调整为int *arr,但不清楚这些发生的顺序。GCC和 Clang 在这一点上有所不同;Clang 计算数组大小,但 GCC 不计算。对于非限定对象n,这没有什么区别,但是,如果n是 挥发性的 或数组大小是具有副作用的其他表达式,则它确实会产生影响。

为什么编译器要查找标识符n,即使它的值不会被使用。

编译器需要解析代码以确定其语法结构。那里可以出现有效的关键字,例如staticconstrestrictvolatile_Atomic。其他关键字可能有错误。或者您可以有其他表达方式,例如n * 3. 如果确实存在n并且它是 an 的标识符int,则编译器可以忽略它。如果有n并且它是函数的标识符,则编译器应该发出诊断消息。无论存在什么,编译器都需要对其进行分析并接受它或发出适当的诊断消息。

参数声明中的数组大小在多维数组中更有用,如void f(size_t m, size_t n, int Array[m][n]). 其中,m如上所述并且可以省略,但是n使用并且是关键的。