Saya baru saja menemukan kode C seseorang yang saya bingung mengapa kompilasi. Ada dua hal yang saya tidak mengerti.
Pertama, prototipe fungsi tidak memiliki parameter dibandingkan dengan definisi fungsi yang sebenarnya. Kedua, parameter dalam definisi fungsi tidak memiliki tipe.
#include <stdio.h>
int func();
int func(param)
{
return param;
}
int main()
{
int bla = func(10);
printf("%d", bla);
}
Mengapa ini bekerja? Saya telah mengujinya di beberapa kompiler, dan itu berfungsi dengan baik.
c
parameters
function-prototypes
function-parameter
AdmiralJonB
sumber
sumber
-Wstrict-prototypes
untukint func()
danint main()
: xc: 3: peringatan: deklarasi fungsi bukan prototipe. Anda harus menyatakanmain()
sebagaimain(void)
juga.int func();
kompatibelint func(arglist) { ... }
.int main(void)
.Jawaban:
Semua jawaban lainnya benar, tetapi hanya untuk penyelesaian
Dan lagi demi kelengkapan. Dari spesifikasi C11 6: 11: 6 (halaman: 179)
sumber
Dalam C
func()
berarti Anda dapat melewati sejumlah argumen. Jika Anda tidak ingin argumen maka Anda harus menyatakan sebagaifunc(void)
. Jenis yang Anda berikan ke fungsi Anda, jika tidak ditentukan secara defaultint
.sumber
func(42,0x42);
(di mana semua panggilan harus menggunakan dua bentuk args).unsigned
hanyalah nama lain untuk tipe yang sama denganunsigned int
.int func();
adalah deklarasi fungsi usang dari hari-hari ketika tidak ada standar C, yaitu hari-hari K&R C (sebelum 1989, tahun standar "ANSI C" pertama diterbitkan).Ingat bahwa tidak ada prototipe dalam K&R C dan kata kunci
void
belum ditemukan. Yang bisa Anda lakukan adalah memberi tahu kompiler tentang jenis kembali fungsi. Daftar parameter kosong dalam K&R C berarti jumlah argumen yang "tidak ditentukan tapi tetap". Tetap berarti bahwa Anda harus memanggil fungsi dengan sama jumlah args setiap kali (sebagai lawan dari variadic fungsi sepertiprintf
, di mana jumlah dan jenis dapat bervariasi untuk setiap panggilan).Banyak kompiler akan mendiagnosis konstruk ini; khususnya
gcc -Wstrict-prototypes
akan memberi tahu Anda "deklarasi fungsi bukan prototipe", yang tepat, karena terlihat seperti prototipe (terutama jika Anda diracuni oleh C ++!), tetapi tidak. Ini adalah deklarasi tipe pengembalian K&R gaya lama.Aturan praktis: Jangan pernah biarkan deklarasi daftar parameter kosong, gunakan
int func(void)
untuk lebih spesifik. Ini mengubah deklarasi tipe pengembalian K&R menjadi prototipe C89 yang tepat. Kompiler senang, pengembang senang, dam statis senang. Mereka yang disesatkan oleh ^ W ^ Wfond dari C ++ mungkin merasa ngeri, karena mereka perlu mengetikkan karakter tambahan ketika mereka mencoba melatih kemampuan bahasa asing mereka :-)sumber
int
.Saya akan menganggap bangunan apa pun yang melewati ini kurang dalam tingkat peringatan / kesalahan yang dikonfigurasi, tidak ada gunanya menjadi ini memungkinkan untuk kode aktual.
sumber
Ini adalah deklarasi dan definisi fungsi gaya K&R . Dari C99 Standard (ISO / IEC 9899: TC3)
Bagian 6.7.5.3 Deklarator Fungsi (termasuk prototipe)
Bagian 6.11.6 Deklarator fungsi
Bagian 6.11.7 Definisi fungsi
Yang gaya lama berarti K & R gaya
Contoh:
Pernyataan:
int old_style();
Definisi:
sumber
C mengasumsikan
int
jika tidak ada tipe yang diberikan pada tipe pengembalian fungsi dan daftar parameter . Hanya untuk aturan ini mengikuti hal-hal aneh yang dimungkinkan.Definisi fungsi terlihat seperti ini.
Jika ini prototipe yang Anda tulis
Dalam prototipe Anda hanya dapat menentukan jenis parameter. Nama parameter tidak wajib. Begitu
Juga jika Anda tidak menentukan tipe parameter tetapi nama
int
diasumsikan sebagai tipe.Jika Anda melangkah lebih jauh, mengikuti pekerjaan juga.
Compiler mengasumsikan
int func()
ketika Anda menulisfunc()
. Tapi jangan dimasukkan kefunc()
dalam tubuh fungsi. Itu akan menjadi panggilan fungsisumber
int func()
bukan bentuk implisit dariint func(int)
.Seperti yang dinyatakan @ Krishnabhadra, semua tanggapan sebelumnya dari pengguna lain, memiliki interpretasi yang benar, dan saya hanya ingin membuat analisis yang lebih rinci dari beberapa poin.
Dalam Old-C seperti dalam ANSI-C " parameter formal yang tidak diketik", ambil dimedion dari register kerja Anda atau kemampuan kedalaman instruksi (shadow register atau instruksi siklus kumulatif), dalam 8bit MPU, akan menjadi int16, dalam 16bit MPU dan seterusnya akan menjadi int16 dan seterusnya, dalam hal arsitektur 64bit dapat memilih untuk mengkompilasi opsi seperti: -m32.
Meskipun tampaknya implementasi lebih mudah pada level tinggi, Untuk melewati beberapa parameter, pekerjaan programmer dalam langkah kontrol tipe data dimencion, menjadi lebih banyak menuntut.
Dalam kasus lain, untuk beberapa arsitektur mikroprosesor, kompiler ANSI menyesuaikan, memanfaatkan beberapa fitur lama ini untuk mengoptimalkan penggunaan kode, memaksa lokasi "parameter formal yang tidak diketik" ini untuk bekerja di dalam atau di luar register kerja, hari ini Anda dapat hampir sama dengan penggunaan "volatile" dan "register".
Tetapi harus dicatat bahwa kompiler paling modern, tidak membuat perbedaan antara dua jenis pernyataan parameter.
Contoh kompilasi dengan gcc di linux:
Bagaimanapun pernyataan prototipe secara lokal tidak ada gunanya, karena tidak ada panggilan tanpa parameter referensi ke prototipe ini akan lalai. Jika Anda menggunakan sistem dengan "parameter formal yang tidak diketik", untuk panggilan eksternal, lanjutkan untuk menghasilkan tipe data prototipe deklaratif.
Seperti ini:
sumber
int
, yang umumnya ukuran register kerja atau 16 bit, mana yang lebih kecil.int
jenis yang tidak mampu memegang semua nilai dalam kisaran - 32767 hingga +32767 (note -32768 tidak diperlukan) dan juga mampu menampung semuachar
nilai (artinya jikachar
16 bit, harus ditandatangani atauint
harus lebih besar).Mengenai tipe parameter, sudah ada jawaban yang benar di sini tetapi jika Anda ingin mendengarnya dari kompiler, Anda dapat mencoba menambahkan beberapa flag (flag hampir selalu merupakan ide yang bagus).
kompilasi program Anda menggunakan
gcc foo.c -Wextra
saya dapatkan:anehnya
-Wextra
tidak menangkap ini karenaclang
(itu tidak mengenali-Wmissing-parameter-type
karena alasan tertentu, mungkin untuk yang historis yang disebutkan di atas) tetapi-pedantic
tidak:Dan untuk masalah prototipe seperti dikatakan di atas
int func()
mengacu pada parameter arbitrer kecuali Anda secara khusus mendefinisikannya sebagaiint func(void)
yang kemudian akan memberi Anda kesalahan seperti yang diharapkan:atau
clang
sebagai:sumber
Jika deklarasi fungsi tidak memiliki parameter yaitu kosong maka itu mengambil jumlah argumen yang tidak ditentukan. Jika Anda ingin membuatnya tidak perlu argumen maka ubah ke:
sumber
Inilah sebabnya saya biasanya menyarankan orang untuk mengkompilasi kode mereka dengan:
Bendera ini memberlakukan beberapa hal:
Bendera ini juga digunakan secara default di banyak proyek Open Source. Sebagai contoh, FreeBSD mengaktifkan flag-flag ini ketika membangun dengan WARNS = 6 di Makefile Anda.
sumber