【发布时间】:2011-07-31 04:58:09
【问题描述】:
C 中这两个函数有什么区别?
void f1(double a[]) {
//...
}
void f2(double *a) {
//...
}
如果我要在一个相当长的数组上调用函数,这两个函数的行为会有所不同,它们会占用更多的堆栈空间吗?
【问题讨论】:
标签: c arrays function parameter-passing space-efficiency
C 中这两个函数有什么区别?
void f1(double a[]) {
//...
}
void f2(double *a) {
//...
}
如果我要在一个相当长的数组上调用函数,这两个函数的行为会有所不同,它们会占用更多的堆栈空间吗?
【问题讨论】:
标签: c arrays function parameter-passing space-efficiency
首先,一些standardese:
6.7.5.3 函数声明符(包括原型)
...
7 将参数声明为“type”的数组应调整为“qualified pointer to type'',其中类型限定符(如果有)是在[和]的 数组类型推导。如果关键字static也出现在[和]的 数组类型推导,然后每次调用函数,对应的值 实际参数应提供对数组的第一个元素的访问,其中至少有 由 size 表达式指定的元素。
因此,简而言之,任何声明为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 不是sizeof 或& 的操作数,因此其类型从“int 的10 元素数组”隐式转换为“指向int 的指针”根据 6.2.3.1/3。因此,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个元素的数组。
【讨论】:
区别纯粹是语法上的。在 C 语言中,当函数参数使用数组表示法时,它会自动转换为指针声明。
【讨论】:
不,它们之间没有区别。为了测试我在 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
所以这个调用的两个版本没有区别,至少编译器对它们的威胁是一样的。
【讨论】: