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 anders verhalten, würden sie mehr Platz auf dem Stapel einnehmen?
Zuerst einige Standardesisch:
6.7.5.3 Funktionsdeklaratoren (einschließlich Prototypen)
…
7 Eine Deklaration eines Parameters als „array of Typ” soll auf ”qualifizierter Zeiger auf angepasst werden
Typ”, wobei die Typqualifizierer (falls vorhanden) diejenigen sind, die in der angegeben sind [
and ]
der Array-Typ-Ableitung. Wenn das Schlüsselwort static
erscheint auch innerhalb der [
and ]
der Array-Typ-Ableitung, dann muss für jeden Aufruf der Funktion der Wert des entsprechenden tatsächlichen Arguments den Zugriff auf das erste Element eines Arrays mit mindestens so vielen Elementen ermöglichen, wie durch den Größenausdruck angegeben.
Kurz gesagt, jeder Funktionsparameter, der als deklariert ist T a[]
oder T a[N]
wird behandelt als ob es wurde erklärt T *a
.
Warum werden Array-Parameter also so behandelt, als wären sie als Zeiger deklariert? Hier ist der Grund:
6.3.2.1 Lvalues, Arrays und Funktionsbezeichner
…
3 Außer wenn es der Operand von ist sizeof
Operator oder das Unäre &
-Operator oder ist ein Zeichenfolgenliteral, das zum Initialisieren eines Arrays verwendet wird, eines Ausdrucks vom Typ „Array of Typ” wird in einen Ausdruck vom Typ ”Zeiger auf Typ”, das auf das Anfangselement des Array-Objekts zeigt und kein Lvalue ist. Wenn das Array-Objekt eine Registerspeicherklasse hat, ist das Verhalten undefiniert.
Angesichts des folgenden Codes:
int main(void)
{
int arr[10];
foo(arr);
...
}
Im Aufruf an foo
der Array-Ausdruck arr
ist auch kein Operand von sizeof
oder &
also wird sein Typ implizit von “10-Element-Array von int
” bis “Zeiger auf int
” nach 6.2.3.1/3. Somit gilt foo
erhält einen Zeigerwert anstelle eines Array-Werts.
Aufgrund von 6.7.5.3/7 können Sie schreiben foo
wie
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 wenn Sie eine Parameterdeklaration wie
void foo(int a[static 10])
{
...
}
der tatsächliche Parameter entspricht a
muss ein Array mit sein wenigstens 10 Elemente.
Der Unterschied ist rein syntaktisch. Wenn in C die Array-Notation für einen Funktionsparameter verwendet wird, wird sie automatisch in eine Zeigerdeklaration umgewandelt.
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 zerlege hauptsächlich Funktion in .exe beider aufrufenden Versionen der Binärdatei in IDA bekomme ich genau den gleichen Assembler-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 bedroht der Compiler sie gleichermaßen.