Quelle est la différence entre les deux fonctions en C?
void f1(double a[]) {
//...
}
void f2(double *a) {
//...
}
Si je devais appeler les fonctions sur un tableau sensiblement long, ces deux fonctions se comporteraient-elles différemment, prendraient-elles plus d'espace sur la pile?
Tout d'abord, quelques standardese :
6.7.5.3 Déclarateurs de fonctions (y compris les prototypes)
...
7 Une déclaration de paramètre comme ‘'tableau de type'' Doit être réglé sur '' 'pointeur qualifié pour type’’, Où les qualificatifs de type (le cas échéant) sont ceux spécifiés dans le[
et]
de la dérivation du type de tableau. Si le mot cléstatic
apparaît également dans le champ[
et]
de la dérivation du type de tableau, puis, pour chaque appel à la fonction, la valeur de l'argument réel correspondant doit permettre d'accéder au premier élément d'un tableau avec au moins autant d'éléments que ceux spécifiés par l'expression de taille.
En bref, tout paramètre de fonction déclaré comme T a[]
ou T a[N]
est traité comme si il avait été déclaré T *a
.
Alors, pourquoi les paramètres de tableau sont-ils traités comme s'ils avaient été déclarés comme des pointeurs? Voici pourquoi:
6.3.2.1 Lvalues, tableaux et indicatifs de fonctions
...
3 Sauf s'il s'agit de l'opérande de l'opérateursizeof
ou du unaire&
opérateur, ou est un littéral utilisé pour initialiser un tableau, une expression de type '' tableau de type'' Est converti en une expression de type '' 'pointeur sur type’’ Qui pointe sur l’élément initial de l’objet tableau et n’est pas une valeur. Si l'objet tableau a une classe de stockage de registre, le comportement n'est pas défini.
Étant donné le code suivant:
int main(void)
{
int arr[10];
foo(arr);
...
}
Dans l'appel à foo
, l'expression de tableau arr
n'est pas un opérande de sizeof
ou &
, son type est donc implicitement converti du "tableau à 10 éléments de int
" en "pointeur sur int
" conformément au 6.2.3.1/3. Ainsi, foo
recevra une valeur de pointeur, plutôt qu'une valeur de tableau.
En raison de 6.7.5.3/7, vous pouvez écrire foo
comme
void foo(int a[]) // or int a[10]
{
...
}
mais il sera interprété comme
void foo(int *a)
{
...
}
Ainsi, les deux formes sont identiques.
La dernière phrase du 6.7.5.3/7 a été introduite avec C99 et signifie fondamentalement que si vous avez une déclaration de paramètre comme
void foo(int a[static 10])
{
...
}
le paramètre réel correspondant à a
doit être un tableau avec au moins 10 éléments.
La différence est purement syntaxique. En C, lorsque la notation de tableau est utilisée pour un paramètre de fonction, il est automatiquement transformé en une déclaration de pointeur.
Non, il n'y a pas de différence entre eux. Pour tester, j'ai écrit ce code C dans le compilateur Dev C++ (mingw):
#include <stdio.h>
void function(int* array) {
int a =5;
}
void main() {
int array[]={2,4};
function(array);
getch();
}
Lorsque je désassemble principal la fonction .exe des deux versions du fichier binaire appelant dans IDA, le code d'assemblage est identique à celui présenté ci-dessous:
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
Donc, il n'y a pas de différence entre les deux versions de cet appel, du moins le compilateur les menace également.