C 中将数组和数组指针传递给函数的区别

发布于 2024-10-31 07:00:12 字数 212 浏览 2 评论 0原文

C 语言中这两个函数有什么区别?

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

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

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

What is the difference between these two functions in C?

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

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

If I were to call the functions on a substantially long array, would these two functions behave differently? Would one use more stack space than the other?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

罗罗贝儿 2024-11-07 07:00:12

首先,一些标准语言

6.7.5.3 函数声明符(包括原型)
...
7 将参数声明为“类型的数组”应调整为“指向的限定指针”
type'',其中类型限定符(如果有)是在 [] 中指定的那些
数组类型推导。如果关键字static也出现在[]
数组类型推导,那么每次调用函数时,都会得到对应的值
实际参数应提供对数组第一个元素的访问,其数量至少与
由大小表达式指定的元素。

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

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

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

给定以下代码:

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

在对 foo 的调用中,数组表达式 arr 不是 sizeof& 的操作数。,因此根据6.2.3.1/3,其类型从“int的10元素数组”隐式转换为“指向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 个元素。

First, some standardese:

6.7.5.3 Function declarators (including prototypes)
...
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many
elements as specified by the size expression.

So, in short, any function parameter declared as T a[] or T a[N] is treated as though it were declared T *a.

So, why are array parameters treated as though they were declared as pointers? Here's why:

6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator or the unary & operator, or is a
string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
the array object and is not an lvalue. If the array object has register storage class, the
behavior is undefined.

Given the following code:

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

In the call to foo, the array expression arr isn't an operand of either sizeof or &, so its type is implicitly converted from "10-element array of int" to "pointer to int" according to 6.2.3.1/3. Thus, foo will receive a pointer value, rather than an array value.

Because of 6.7.5.3/7, you can write foo as

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

but it will be interpreted as

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

Thus, the two forms are identical.

The last sentence in 6.7.5.3/7 was introduced with C99, and basically means that if you have a parameter declaration like

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

the actual parameter corresponding to a must be an array with at least 10 elements.

横笛休吹塞上声 2024-11-07 07:00:12

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

The difference is purely syntaxic. In C, when the array notation is used for a function parameter, it is automatically transformed into a pointer declaration.

爱你是孤单的心事 2024-11-07 07:00:12

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

#include <stdio.h>

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

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

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

当我在 IDA 中的两个调用版本的二进制文件的 .exe 中反汇编 ma​​in 函数时,我得到完全相同的汇编代码,如下所示 此调用的两个版本之间没有区别,至少编译器对它们的威胁相同。

No, there is no difference between them. To test I wrote this C code in Dev C++(mingw) compiler:

#include <stdio.h>

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

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

When I disassemble main function in .exe of both calling versions of binary file in IDA I get exactly the same assembly code like below:

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

So there is no difference between the two versions of this call, at least the compiler threats them equally.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文