这个问题建立在this one的基础上,它描述了以下内容是如何等效的:
int f(int a[10]) { ... } // the 10 makes no difference
int f(int a[]) { ... }
int f(int *a) { ... }
字符串
在有关Function prototype scope的文档中,提供了以下示例:
int f(int n, int a[n]); // n is in scope, refers to first param
型
这就引出了一个问题:在何种程度上,以下内容是等价的:
// 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
型
结论性问题:
- 假设
int f(int arr[n])
和int f(int *arr)
都可以编译,那么它们总是等价的吗? - 为什么编译器要查找标识符
n
,即使它的值不会被使用。 - 我猜:在源代码中包含
n
的唯一原因是作为文档来指示数组应该具有的最小长度。确保n
在范围内,并且具有正确的类型,确保此文档有意义
2条答案
按热度按时间bxfogqkk1#
假设
int f(int arr[n])
和int f(int *arr)
都可以编译,那么它们总是等价的吗?C标准在这一点上是有缺陷的;它没有说明
int arr[n]
中的n
是否被评估。int arr[n]
名义上声明了一个可变长度数组(假设n
是某个对象的标识符,而不是常量的宏)。C标准说,可变长度数组的大小会被评估,它还说参数声明int arr[n]
会自动调整为int *arr
,但不清楚这些在. GCC and Clang differ on this point中出现的顺序; Clang计算数组大小,但GCC不计算。对于非限定对象n
,这没有区别,但是,如果n
是volatile的,或者数组大小是其他有副作用的表达式,它确实有区别。为什么编译器要查找标识符
n
,即使它的值不会被使用。编译器需要解析代码以确定其语法结构。可以在那里出现有效的关键字,例如
static
,const
,restrict
,volatile
和_Atomic
。其他关键字可能是错误的。或者您可以使用其他表达式,例如n * 3
。如果你有n
,并且它是int
的标识符,编译器可以忽略它。如果你有n
,并且它是一个函数的标识符,编译器应该发出一个诊断消息。无论那里有什么,编译器需要对其进行分析,并接受它或发出适当的诊断消息。参数声明中的数组大小在多维数组中更有用,如
void f(size_t m, size_t n, int Array[m][n])
。在这里,m
如上所述,可以省略,但n
被使用,并且是关键的。iyr7buue2#
对于初学者,根据C标准(6.7.6.3函数声明符(包括原型)):
7将参数声明为“array of type”应调整为“qualified pointer to type”,其中类型限定符(如果有的话)是在数组类型派生的[ and ]中指定的那些。如果关键字static也出现在数组类型派生的[ and ]中,则对于每次调用函数,对应的实际参数的值将提供对数组的第一个元素的访问,该数组至少具有与size表达式指定的元素一样多的元素。
其次(6.7.6.2数组声明符)
4如果size不存在,则数组类型为不完整类型。如果size为 * 而不是表达式,则数组类型为未指定大小的变长数组类型,只能在声明或具有函数原型作用域的类型名中使用; 146)这样的数组仍然是完整类型。如果大小是整数常量表达式并且元素类型具有已知的常量大小,数组类型不是可变长度数组类型;否则,数组类型是可变长度数组类型。(可变长度数组是实现不需要支持的条件特性;参见6.10.8.3。)
C标准中第一个引号中突出显示的短语适用于具有可变长度数组类型、不可变数组类型(当数组的大小由整数常量表达式指定时)和不完整数组类型的参数声明。
在这个函数声明的例子中,
字符串
具有数组类型的参数由编译器调整为指向数组元素类型的指针。因此所有三个函数声明(注意必须提供一个定义)都声明了同一个函数。
这同样适用于这个函数声明的例子
型
在第一个声明中,第二个参数具有可变长度数组类型。
型
至于第三个例子
型
然后如果
n
没有在第一个函数声明之前在文件作用域中声明,那么编译器显然会发出一个错误,即标识符(或名称)n
没有声明。但是如果变量n
将在函数声明之前声明,那么上述两个声明将是等价的。这是一个演示程序
型
程序输出为
型