Setelah melihat (dan bertanya!) Begitu banyak pertanyaan yang mirip
Apa yang dimaksud
int (*f)(int (*a)[5])
dengan C?
dan bahkan melihat bahwa mereka membuat program untuk membantu orang memahami sintaks C, saya bertanya-tanya:
Mengapa sintaks C dirancang dengan cara ini?
Misalnya, jika saya mendesain pointer, saya akan menerjemahkan "pointer ke array 10-elemen pointer" menjadi
int*[10]* p;
dan tidak
int* (*p)[10];
yang saya rasa kebanyakan orang akan setuju jauh lebih mudah.
Jadi saya bertanya-tanya, mengapa, eh, sintaks tidak intuitif? Apakah ada masalah khusus yang diselesaikan oleh sintaksis (mungkin ambiguitas?) Yang tidak saya sadari?
cdecl
Perintah ini sangat berguna untuk decoding C deklarasi kompleks. Ada juga antarmuka web di cdecl.org .Jawaban:
Pemahaman saya tentang sejarahnya adalah bahwa itu didasarkan pada dua poin utama ...
Pertama, penulis bahasa lebih suka membuat sintaks variabel-sentris daripada tipe-sentris. Artinya, mereka ingin seorang programmer untuk melihat deklarasi dan berpikir "jika saya menulis ekspresi
*func(arg)
, itu akan menghasilkanint
; jika saya menulis*arg[N]
saya akan memiliki float" daripada "func
harus menjadi pointer ke fungsi yang mengambil ini dan mengembalikan itu ".The C entri di Wikipedia mengklaim bahwa:
... mengutip p122 dari K & R2 yang, sayangnya, saya tidak perlu menyerahkan untuk menemukan kutipan diperpanjang untuk Anda.
Kedua sebenarnya sangat, sangat sulit untuk menghasilkan sintaks untuk deklarasi yang konsisten ketika Anda berurusan dengan tingkat tipuan yang sewenang-wenang. Contoh Anda mungkin bekerja dengan baik untuk mengekspresikan tipe yang Anda pikirkan di luar sana, tetapi apakah itu skala ke fungsi mengambil pointer ke array jenis tersebut, dan mengembalikan beberapa kekacauan mengerikan lainnya? (Mungkin benar, tetapi apakah Anda memeriksa? Bisakah Anda membuktikannya? ).
Ingat, bagian dari keberhasilan C adalah karena fakta bahwa kompiler ditulis untuk banyak platform yang berbeda, dan mungkin lebih baik untuk mengabaikan beberapa tingkat keterbacaan demi membuat kompiler lebih mudah untuk ditulis.
Karena itu, saya bukan ahli tata bahasa atau penulisan kompiler. Tapi saya cukup tahu untuk tahu ada banyak yang tahu;)
sumber
Banyak keanehan dari bahasa C dapat dijelaskan dengan cara komputer bekerja saat itu dirancang. Ada jumlah memori penyimpanan yang sangat terbatas, sehingga sangat penting untuk meminimalkan ukuran file kode sumber itu sendiri. Praktek pemrograman kembali pada tahun 70-an dan 80-an adalah untuk memastikan kode sumber mengandung karakter sesedikit mungkin, dan lebih disukai tidak ada komentar kode sumber yang berlebihan.
Ini tentu saja konyol hari ini, dengan ruang penyimpanan yang tidak terbatas pada hard drive. Tetapi itu adalah bagian dari alasan mengapa C memiliki sintaks aneh seperti itu pada umumnya.
Mengenai pointer array khusus, contoh kedua Anda seharusnya
int (*p)[10];
(yeah sintaksnya sangat membingungkan). Saya mungkin akan membacanya sebagai "int pointer to array of sepuluh" ... yang agak masuk akal. Jika bukan untuk kurung, kompiler akan menafsirkannya sebagai array dari sepuluh petunjuk saja, yang akan memberikan deklarasi makna yang sama sekali berbeda.Karena array pointer dan pointer fungsi keduanya memiliki sintaks yang cukup tidak jelas dalam C, hal yang masuk akal untuk dilakukan adalah mengetikkan keanehannya. Mungkin seperti ini:
Contoh tidak jelas:
Contoh tidak setara, tidak jelas:
Hal-hal bisa menjadi lebih tidak jelas jika Anda berurusan dengan array pointer fungsi. Atau yang paling tidak jelas dari semuanya: fungsi mengembalikan fungsi pointer (sedikit berguna). Jika Anda tidak menggunakan typedefs untuk hal-hal seperti itu, Anda akan dengan cepat menjadi gila.
sumber
Ini sangat sederhana:
int *p
artinya*p
int;int a[5]
berarti itua[i]
int.Berarti itu
*f
adalah suatu fungsi,*a
adalah array dari lima bilangan bulat, demikianf
juga fungsi mengambil pointer ke array dari lima bilangan bulat, dan mengembalikan int. Namun, dalam C tidak berguna untuk meneruskan pointer ke array.Deklarasi C sangat jarang mendapatkan ini rumit.
Anda juga dapat mengklarifikasi menggunakan typedefs:
sumber
typedef
,const
,volatile
, dan kemampuan untuk menginisialisasi hal dalam deklarasi. Banyak ambiguitas sintaksis deklarasi yang menjengkelkan (mis. Apakahint const *p, *q;
harus mengikatconst
ke tipe atau deklarasi) tidak dapat muncul dalam bahasa yang dirancang semula. Saya berharap bahasa telah menambahkan titik dua antara tipe dan deklarand, tetapi memungkinkan penghilangan ketika menggunakan built-in "kata-kata" tipe tanpa kualifikasi. Artiint: const *p,*q;
danint const *: p,*q;
pasti sudah jelas.Saya pikir Anda harus mempertimbangkan * [] sebagai operator yang dilampirkan ke variabel. * ditulis sebelum variabel, [] setelah.
Mari kita baca ekspresi tipe
Elemen terdalam adalah p, variabel, oleh karena itu
berarti: p adalah variabel.
Sebelum variabel ada *, operator * selalu diletakkan sebelum ekspresi yang dimaksud, oleh karena itu,
berarti: variabel p adalah sebuah pointer. Tanpa () operator [] ke kanan akan memiliki prioritas lebih tinggi, yaitu
akan diurai sebagai
Langkah selanjutnya adalah []: karena tidak ada lagi (), [] memiliki prioritas lebih tinggi daripada * luar, oleh karena itu
berarti: (variabel p adalah pointer) ke array. Maka kita memiliki yang kedua *:
berarti: ((variabel p adalah pointer) ke array) dari pointer
Akhirnya Anda memiliki operator int (nama jenis), yang memiliki prioritas terendah:
berarti: (((variabel p adalah pointer) ke array) dari pointer) ke integer.
Jadi seluruh sistem didasarkan pada ekspresi tipe dengan operator, dan masing-masing operator memiliki aturan diutamakan sendiri. Ini memungkinkan untuk mendefinisikan tipe yang sangat kompleks.
sumber
Tidak begitu sulit ketika Anda mulai berpikir dan bahasa C tidak pernah mudah. Dan
int*[10]* p
benar-benar tidak mudah daripadaint* (*p)[10]
Dan apa jenis k akan masukint*[10]* p, k;
sumber
pointer to int
danint
bahkan bukan tipe yang sama, sehingga harus dinyatakan secara terpisah. Titik. Dengarkan pria itu. Dia memiliki 18k perwakilan karena suatu alasan.