2011-04-06 19 views
88

işlevine geçirme arasındaki fark C'deki iki işlev arasındaki fark nedir? Diziyi ve dizi işaretçisini C

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

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

Ben esas uzun dizi işlevleri çağırmak için olsaydı

, bu iki işlev, yığının daha fazla yer alacağını, farklı davranabilir ki?

cevap

96

Birincisi, bazı standardese: (prototipler dahil)

6.7.5.3 Fonksiyon declarators
... ' tip dizisi' 'gibi bir parametrenin
7 bildirgede' olacaktır tür '' nitelikli işaretçiye '' olarak ayarlanmışsa, burada tür niteleyiciler (varsa),vedizi türü türevlerinin ] içinde belirtilenlerdir siyon. Anahtar static da [ ve dizi türü türetme ] görünürse, o zaman işlevi, her biri için karşılık gelen gerçek bağımsız değişken değerinin, en az bir çok ile bir dizi birinci elemanına erişimi sağlayacaktır boyut ifadesiyle belirtilen öğeler. o T *a ilan edildi sanki Yani, kısacası, herhangi bir fonksiyon parametresi T a[] veya T a[N] olarak ilan

tedavi edilir.

Peki, dizi parametreleri neden işaretçi olarak bildirilmiş gibi ele alınır? İşte nedenleri:

6.3.2.1 SolDeğerler, diziler ve işlev koordinat belirleme o sizeof operatör veya tekli & operatörün terimidir ve ya bir dize olduğu zamanlar hariç
...
3 bir dizi başlatmak için kullanılan, ' tür' 'dizisi olan bir ifade dizisi nesnesinin ilk öğesinin işaret ettiği' 'işaretçisine tür' 'ile bir ifadeye dönüştürülür ve bir değer değil. Dizi nesnesinin kayıt defteri sınıfı varsa, davranışı tanımsızdır.

aşağıdaki kodu verilen: bunun türü örtülü "10-elemanlı bir dizinin dönüştürülür, böylece

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

çağrısında foo için, dizi sentezleme arr ya sizeof veya & bir işlenen değildir 6.2.3.1/3'e göre "int" ile "int işaretçisini" gösterir. Böylece, foo bir dizi değeri yerine bir işaretçi değeri alacaktır.

6.7.5.3/7 yüzümden, foo

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

yazabilir ama

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

Böylece iki biçimi aynıdır gibi yorumlanır.

6.7.5.3/7 son sözünün C99 ile tanıtıldı ve temelde

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

gibi bir parametre beyanı varsa a tekabül gerçek parametre en az ile bir dizi olmalıdır anlamına gelir oldu 10 öğeler.

+1

(En azından biraz daha eski) MSVC C++ derleyicileri kullanırken, derleyicinin işlev adının iki durumda farklı şekilde yanlış bir şekilde yönetilmesi nedeniyle bir fark vardır (başka türüyle aynı olduklarını kabul ederken), bağlantı sorunlarıyla sonuçlanır. Hata raporunu burada göremezsiniz http://connect.microsoft.com/VisualStudio/feedback/details/326874/inconsistent-name-mangling-for-functions-accepting-array-and-pointer-parameters – greggo

27

Bu fark tamamen sözdizimidir. C'de, bir işlev parametresi için dizi gösterimi kullanıldığında, otomatik olarak bir işaretçi bildirimine dönüştürülür.

+1

@Kaushik: Bu durumda aynı olsalar da, aynı durumda olmadıklarını unutmayın [genel durumda] (http://stackoverflow.com/questions/2096448/do-these-statements-about -pointers-have-the-same-effect) –

+0

@BlueRaja: evet, bu, C'nin tuzaklarından biridir. İşlevsel parametrelerin beyanı, yerel değişkenlerin beyanı için _very benzeridir, ancak birkaç ince fark vardır (Bu programlayıcıyı ısırmaya eğilimli bu dizi-işaretçi otomatik dönüşümü). –

-2

Hayır, aralarında fark yoktur. Ben IDA ikili dosyanın hem çağıran versiyonlarının .exe içinde ana fonksiyonunu sökerken

#include <stdio.h> 

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

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

ben de aynı montaj kod aşağıda gibi olsun: (mingw) derleyici ++ Ben Dev C bu C kodu yazdım sınamak için :

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 

Yani bu çağrının iki sürümü arasındaki fark, en azından derleyici tehditler onları eşit vardır.

+15

Üzgünüm, ancak bu sadece gcc'nin her ikisinin de x86'da aynı montajı oluşturduğunu kanıtlıyor. Doğru cevap, yanlış açıklama. – lambdapower