Saya menemukan teka-teki C berikut:
T: Mengapa program berikut dipisahkan pada IA-64, tetapi berfungsi dengan baik pada IA-32?
int main()
{
int* p;
p = (int*)malloc(sizeof(int));
*p = 10;
return 0;
}
Saya tahu bahwa ukuran int
pada mesin 64 bit mungkin tidak sama dengan ukuran pointer ( int
bisa 32 bit dan pointer bisa 64 bit). Tetapi saya tidak yakin bagaimana ini berhubungan dengan program di atas. Ada ide?
c
pointers
segmentation-fault
pengguna7
sumber
sumber
stdlib.h
tidak disertakan?#include stdlib.h
(untuk malloc)#include <stdlib.h>
, itu ditemukan dengan sempurna, tetapi itu bukan pertanyaannya.sizeof(int) == sizeof(int*)
, jika misalnya pointer dikembalikan melalui register yang berbedaint
dalam konvensi pemanggilan yang digunakan.malloc()
. GCC mengatakan:warning: incompatible implicit declaration of built-in function 'malloc'
juga.Jawaban:
Para pemeran untuk
int*
menutupi fakta bahwa tanpa#include
tipe pengembalian yang tepatmalloc
diasumsikanint
. IA-64 kebetulan memilikisizeof(int) < sizeof(int*)
yang membuat masalah ini menjadi jelas.(Perhatikan juga bahwa karena perilaku tidak terdefinisi, ia masih bisa gagal bahkan pada platform yang
sizeof(int)==sizeof(int*)
memegang true, misalnya jika konvensi pemanggil menggunakan register yang berbeda untuk mengembalikan pointer daripada bilangan bulat)The comp.lang.c FAQ memiliki entri membahas mengapa casting kembali dari
malloc
tidak pernah diperlukan dan berpotensi buruk .sumber
new
dalam C ++ dan selalu mengompilasi C dengan kompiler C dan bukan kompilator C ++.int
jika tidak diketahuimalloc
)void*
. Tetapi kode pemanggil menganggap fungsi tersebut kembaliint
(karena Anda memilih untuk tidak memberi tahu sebaliknya), jadi ia mencoba membaca nilai yang dikembalikan sesuai dengan konvensi pemanggilan untukint
. Oleh karena itup
tidak tidak selalu menunjuk ke memori yang dialokasikan. Kebetulan bekerja untuk IA32 karena anint
dan avoid*
berukuran sama, dan dikembalikan dengan cara yang sama. Pada IA64 Anda mendapatkan nilai yang salah.Kemungkinan besar karena Anda tidak menyertakan file header untuk
malloc
dan, sementara kompiler biasanya memperingatkan Anda tentang hal ini, fakta bahwa Anda secara eksplisit mentransmisikan nilai yang dikembalikan berarti Anda memberi tahu bahwa Anda tahu apa yang Anda lakukan.Itu berarti kompilator mengharapkan sebuah
int
dikembalikan darimalloc
mana ia kemudian ditransmisikan ke sebuah pointer. Jika ukurannya berbeda, itu akan membuat Anda sedih.Inilah sebabnya mengapa Anda tidak pernah mentransmisikan
malloc
pengembalian dalam C. Yangvoid*
dikembalikan akan secara implisit dikonversi ke penunjuk dari jenis yang benar (kecuali Anda belum menyertakan header dalam hal ini mungkin akan memperingatkan Anda tentang int- yang berpotensi tidak aman. konversi ke penunjuk).sumber
void *
dapat dikonversi ke tipe pointer lainnya secara implisit.int *p = malloc(sizeof(int))
berfungsi jika prototipe yang tepat ada dalam cakupan dan gagal jika tidak (karena hasilnya diasumsikan seperti ituint
). Dengan cast, keduanya akan dikompilasi dan yang terakhir akan menghasilkan error saatsizeof(int) != sizeof(void *)
.stdlib.h
, kompilator tidak tahumalloc
dan juga tipe kembaliannya. Jadi itu hanya mengasumsikanint
sebagai default.Inilah sebabnya mengapa Anda tidak pernah mengompilasi tanpa peringatan tentang prototipe yang hilang.
Pemeran diperlukan untuk kompatibilitas C ++. Ada sedikit alasan (baca: tidak ada alasan di sini) untuk menghilangkannya.
Kompatibilitas C ++ tidak selalu diperlukan, dan dalam beberapa kasus tidak memungkinkan sama sekali, tetapi dalam banyak kasus hal ini sangat mudah dicapai.
sumber