C'deki iki işlev arasındaki fark nedir?
void f1(double a[]) {
//...
}
void f2(double *a) {
//...
}
İşlevleri büyük ölçüde uzun bir dizide çağıracak olsaydım, bu iki işlev farklı davranır mıydı, yığın üzerinde daha fazla yer kaplar mıydı?
C'deki iki işlev arasındaki fark nedir?
void f1(double a[]) {
//...
}
void f2(double *a) {
//...
}
İşlevleri büyük ölçüde uzun bir dizide çağıracak olsaydım, bu iki işlev farklı davranır mıydı, yığın üzerinde daha fazla yer kaplar mıydı?
Yanıtlar:
İlk olarak, bazı standartlar :
6.7.5.3 Fonksiyon tanımlayıcıları (prototipler dahil)
...
7 Bir parametrenin '' tip dizisi '' olarak bildirimi , tip niteleyicilerinin (varsa) belirtilenler olduğu '' tipe uygun işaretçi '' olarak ayarlanacaktır. içinde[
ve]
dizi türü türetilmesi. Anahtar kelime , dizi türü türetmenin vestatic
içinde de görünüyorsa , işleve yapılan her çağrı için, karşılık gelen gerçek bağımsız değişkenin değeri, boyut tarafından belirtilen en az sayıda öğeye sahip bir dizinin ilk öğesine erişim sağlayacaktır. ifadesi.[
]
Yani, kısacası, herhangi bir fonksiyon parametresi olarak ilan T a[]
veya T a[N]
tedavi edilir sanki o ilan edildi T *a
.
Öyleyse, neden dizi parametreleri işaretçi olarak bildirilmiş gibi davranılıyor? İşte nedeni:
6.3.2.1 SolDeğerler, diziler ve işlev koordinat belirleme
...
bunun işlenen olduğunda hariç 3sizeof
operatör veya tekli&
operatör veya bir diziyi başlatmak için kullanılan bir dize, türü '' dizisi olan bir ifadedir türü ' ', dizi nesnesinin ilk öğesine işaret eden ve bir l değeri olmayan' ' tipe işaretçi' 'türüne sahip bir ifadeye dönüştürülür . Dizi nesnesinin kayıt depolama sınıfı varsa, davranış tanımsızdır.
Aşağıdaki kod verildiğinde:
int main(void)
{
int arr[10];
foo(arr);
...
}
Çağrıda foo
, dizi ifadesi arr
ya ya sizeof
da işlenenlerinden biri değildir &
, bu nedenle türü örtük olarak 6.2.3.1/3 uyarınca "10 elemanlı dizi int
" den "işaretçi int
" ye dönüştürülür. Böylece, foo
bir dizi değeri yerine bir işaretçi değeri alacaktır.
6.7.5.3/7 nedeniyle şu şekilde yazabilirsiniz foo
:
void foo(int a[]) // or int a[10]
{
...
}
ama şu şekilde yorumlanacak
void foo(int *a)
{
...
}
Bu nedenle, iki form aynıdır.
6.7.5.3 / 7'deki son cümle C99 ile tanıtıldı ve temel olarak şu anlama gelir:
void foo(int a[static 10])
{
...
}
değerine karşılık gelen gerçek parametre a
, en az 10 öğeli bir dizi olmalıdır .
Fark tamamen sözdizimseldir. C'de, dizi gösterimi bir işlev parametresi için kullanıldığında, otomatik olarak bir işaretçi bildirimine dönüştürülür.
Hayır, aralarında bir fark yok. Test etmek için bu C kodunu Dev C ++ (mingw) derleyicisine yazdım:
#include <stdio.h>
void function(int* array) {
int a =5;
}
void main() {
int array[]={2,4};
function(array);
getch();
}
IDA'da ikili dosyanın her iki çağıran sürümünün .exe'deki ana işlevi parçalarına ayırdığımda, aşağıdaki gibi tam olarak aynı derleme kodunu alıyorum:
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 versiyonu arasında bir fark yok, en azından derleyici onları eşit şekilde tehdit ediyor.