126

C中的两个函数有什么区别?

void f1(double a[]) {
   //...
}

void f2(double *a) {
   //...
}

如果我要在一个相当长的数组上调用函数,这两个函数的行为会有所不同,它们会在堆栈上占用更多空间吗?

4

3 回答 3

127

首先,一些标准

6.7.5.3 函数声明符(包括原型)
......
7 将参数声明为“类型数组”应调整为“ 类型限定符”,其中类型限定符(如果有)是指定的在数组类型派生的[and中。]如果关键字static也出现在数组类型派生的[and]中,那么对于函数的每次调用,对应的实际参数的值应提供对数组的第一个元素的访问,该数组的元素至少与大小指定的一样多表达。

因此,简而言之,任何声明为T a[]或的函数参数T a[N]都被视为声明T *a

那么,为什么数组参数被视为被声明为指针呢?原因如下:

6.3.2.1 左值、数组和函数指示符
...
3 除非它是运算sizeof符或一元&运算符的操作数,或者是用于初始化数组的字符串文字,否则表达式类型为 ''array of type ' ' 被转换为类型为 ''pointer to type '' 的表达式,它指向数组对象的初始元素并且不是左值。如果数组对象具有寄存器存储类,则行为未定义。

给定以下代码:

int main(void)
{
  int arr[10];
  foo(arr);
  ...
}

在对 的调用中foo,数组表达式arr不是sizeofor的操作数,因此根据 6.2.3.1/3 &,其类型从“10 元素数组int”隐式转换为“指针”。int因此,foo将接收一个指针值,而不是一个数组值。

因为 6.7.5.3/7,你可以foo写成

void foo(int a[]) // or int a[10]
{
  ...
}

但它会被解释为

void foo(int *a)
{
  ...
}

因此,这两种形式是相同的。

6.7.5.3/7 中的最后一句是用 C99 引入的,基本上意味着如果你有一个参数声明,比如

void foo(int a[static 10])
{
  ...
}

对应的实际参数a必须是一个至少有10 个元素的数组。

于 2011-04-06T22:29:20.683 回答
32

区别纯粹是语法上的。在 C 中,当数组表示法用于函数参数时,它会自动转换为指针声明。

于 2011-04-06T21:42:42.113 回答
0

不,它们之间没有区别。为了测试我在 Dev C++(mingw) 编译器中编写了这个 C 代码:

#include <stdio.h>

void function(int* array) {
     int a =5;
}

void main() {  
     int array[]={2,4};
     function(array);
     getch();
}

当我在 IDA 中反汇编两个调用版本的二进制文件的 .exe 中的main函数时,我得到完全相同的汇编代码,如下所示:

push    ebp
mov     ebp, esp
sub     esp, 18h
and     esp, 0FFFFFFF0h
mov     eax, 0
add     eax, 0Fh
add     eax, 0Fh
shr     eax, 4
shl     eax, 4
mov     [ebp+var_C], eax
mov     eax, [ebp+var_C]
call    sub_401730
call    sub_4013D0
mov     [ebp+var_8], 2
mov     [ebp+var_4], 4
lea     eax, [ebp+var_8]
mov     [esp+18h+var_18], eax
call    sub_401290
call    _getch
leave
retn

所以这个调用的两个版本之间没有区别,至少编译器同样威胁它们。

于 2011-04-06T21:54:02.307 回答