2011-04-06 9 views

Respuesta

96

En primer lugar, algunos standardese:

6.7.5.3 declaradores de función (incluyendo prototipos)
...
7 Una declaración de un parámetro como '' variedad de tipo '' será ajustado a '' puntero calificado a tipo '', donde los calificadores de tipo (si los hay) son los especificados en [ y ] de tipo de matriz derivada ción. Si la palabra clave static también aparece dentro del [ y derivación del tipo de matriz, entonces para cada llamada a la función, el valor del correspondiente argumento actual proporcionará acceso al primer elemento de una matriz con al menos elementos según lo especificado por la expresión de tamaño.

Así que, en resumen, cualquier parámetro de la función declarada como T a[] o T a[N] es tratado como si que fueron declarados T *a.

Entonces, ¿por qué los parámetros de matriz se tratan como si se hubieran declarado como punteros? He aquí por qué:

6.3.2.1 Lvalues, arrays y designadores de función
...
3 Excepto cuando es el operando del operador o la sizeof & unario operador, o es una cadena literal utilizado para inicializar una matriz, una expresión que tiene tipo '' matriz de tipo '' es convertida a una expresión con el tipo '' puntero a tipo '' que apunta al elemento inicial de el objeto de matriz y es no es un lvalue Si el objeto de matriz tiene una clase de almacenamiento de registro, el comportamiento de no está definido.

Dado el siguiente código:

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

En la llamada a foo, la expresión de matriz arr no es un operando de cualquiera sizeof o &, por lo que su tipo se convierte implícitamente a partir de "matriz de 10 elementos de int puntero "a" int "de acuerdo con 6.2.3.1/3. Por lo tanto, foo recibirá un valor de puntero, en lugar de un valor de matriz.

Debido a 6.7.5.3/7, se puede escribir como foo

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

pero será interpretado como

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

Por lo tanto, las dos formas son idénticas.

La última frase en 6.7.5.3/7 se introdujo con C99, y básicamente significa que si usted tiene una declaración de parámetros como

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

el parámetro real correspondiente a a debe ser una matriz con al menos 10 elementos.

+1

Existe una diferencia cuando se usan compiladores MSVC C++ (al menos algunos más antiguos), debido a que el compilador manipula incorrectamente el nombre de la función de manera diferente en los dos casos (aunque reconoce que son los mismos), lo que provoca problemas de enlace. Consulte el informe de errores "No se solucionará" aquí http://connect.microsoft.com/VisualStudio/feedback/details/326874/inconsistent-name-mangling-for-functions-accepting-array-and-pointer-parameters – greggo

27

La diferencia es puramente sintáctica. En C, cuando la notación de matriz se usa para un parámetro de función, se transforma automáticamente en una declaración de puntero.

+1

@Kaushik: Aunque son lo mismo en este caso, tenga en cuenta que no son lo mismo [en el caso general] (http://stackoverflow.com/questions/2096448/do-these-statements-about -pointers-have-the-same-effect) –

+0

@BlueRaja: sí, es una de las trampas de C. La declaración de parámetros de función es muy similar a la declaración de variables locales, pero hay algunas diferencias sutiles (tales como esta transformación automática de matriz a puntero) que son propensos a morder al programador incauto. –

-2

No, no hay diferencia entre ellos. Para probar que escribí este código C en Dev C++ (MinGW) compilador:

#include <stdio.h> 

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

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

Cuando desmonte función principal en .exe de ambas versiones de llamada del archivo binario en AIF me sale exactamente el mismo código de montaje, como a continuación :

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 

Así que no hay diferencia entre las dos versiones de esta llamada, al menos el compilador las amenaza por igual.

+15

Lo sentimos, pero esto solo prueba que alguna versión de gcc genera el mismo ensamblado en x86 para ambos. Respuesta correcta, explicación incorrecta. – lambdapower

Cuestiones relacionadas