it-swarm.com.de

Unterschied zwischen der Übergabe von Array und Array-Zeiger in Funktion in C

Was ist der Unterschied zwischen den beiden Funktionen in C?

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

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

Wenn ich die Funktionen in einem sehr langen Array aufrufen würde, würden sich diese beiden Funktionen unterschiedlich verhalten, würden sie mehr Platz auf dem Stapel beanspruchen?

101
Kaushik Shankar

Zunächst einige Standard :

6.7.5.3 Funktionsdeklaratoren (einschließlich Prototypen)
...
7 Eine Deklaration eines Parameters als Array von art"" Muss auf "" qualifizierter Zeiger auf "eingestellt werden art’’, Wobei die Typqualifizierer (falls vorhanden) diejenigen sind, die in [ und ] der Array-Typableitung angegeben sind. Wenn das Schlüsselwort static auch in [ und ] der Array-Typableitung vorkommt, muss für jeden Funktionsaufruf der Wert des entsprechenden tatsächlichen Arguments angegeben werden Ermöglichen Sie den Zugriff auf das erste Element eines Arrays mit mindestens so vielen Elementen, wie durch den Größenausdruck angegeben.

Kurz gesagt, jeder Funktionsparameter, der als T a[] oder T a[N] deklariert wurde, wird so behandelt , als wäre er deklariert T *a.

Warum werden Array-Parameter so behandelt, als wären sie als Zeiger deklariert? Hier ist der Grund:

6.3.2.1 L-Werte, Arrays und Funktionsbezeichner
...
3 Außer wenn es sich um den Operanden des Operators sizeof oder den unären Operator & handelt oder um ein Zeichenfolgenliteral zum Initialisieren eines Arrays handelt, einen Ausdruck vom Typ ' 'Anordnung von art"" Wird in einen Ausdruck vom Typ "Zeiger auf" konvertiert art’’ Zeigt auf das ursprüngliche Element des Array-Objekts und ist kein lWert. Wenn das Array-Objekt über eine Registerspeicherklasse verfügt, ist das Verhalten undefiniert.

Mit folgendem Code:

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

Im Aufruf von foo ist der Array-Ausdruck arr kein Operand von sizeof oder &, daher wird sein Typ implizit konvertiert von " 10-Element-Array von int "bis" Zeiger auf int "gemäß 6.2.3.1/3. Daher erhält foo einen Zeigerwert und keinen Arraywert.

Aufgrund von 6.7.5.3/7 können Sie foo als schreiben

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

aber es wird interpretiert als

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

Somit sind die beiden Formen identisch.

Der letzte Satz in 6.7.5.3/7 wurde mit C99 eingeführt und bedeutet im Grunde, dass Sie eine Parameterdeklaration wie haben

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

der aktuelle Parameter, der a entspricht, muss ein Array mit mindestens 10 Elementen sein.

107
John Bode

Der Unterschied ist rein syntaktisch. Wenn in C die Array-Notation für einen Funktionsparameter verwendet wird, wird sie automatisch in eine Zeigerdeklaration umgewandelt.

28
Thomas Pornin

Nein, es gibt keinen Unterschied zwischen ihnen. Zum Testen habe ich diesen C-Code im Dev C++ (mingw) -Compiler geschrieben:

#include <stdio.h>

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

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

Wenn ich main function in .exe von beiden aufrufenden Versionen der Binärdatei in IDA zerlege, erhalte ich genau den gleichen Assembly-Code wie unten:

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

Es gibt also keinen Unterschied zwischen den beiden Versionen dieses Aufrufs, zumindest der Compiler bedroht sie gleichermaßen.

0
mcaaltuntas