Dalam C, *
disebut operator tidak langsung atau operator dereference. Saya mengerti cara kerjanya saat digunakan dalam pernyataan. Masuk akal untuk menulis *p
atau * p
, mengingat itu adalah operator unary.
Namun, terkadang dalam deklarasi, a *
digunakan.
void move(int *units) { ... }
atau
int *p = &x;
Rasanya aneh bagi saya bahwa operator digunakan di sini. Anda tidak dapat melakukan hal-hal seperti
void move(int units++) { ... }
dimana ++
juga merupakan operator unary. Apakah ini *
juga operator tipuan, atau apakah ini *
memiliki arti yang berbeda, di mana ia mengatakan sesuatu tentang tipe pointer? (Jika ini masalahnya, saya mempertimbangkan untuk menggunakan misalnya int* units
dalam deklarasi dan int x = *p;
sebaliknya untuk kejelasan.)
Dalam hal ini jawaban dikatakan bahwa
Standar C hanya mendefinisikan dua arti bagi operator *:
- operator tipuan
- operator perkalian
Saya juga melihat orang mengklaim bahwa *
itu sebenarnya bagian dari tipe. Ini membingungkan saya.
void move(int *units) { ... }
, itu adalah operator tidak langsung. Dianggap sebagai bagian dari tipe, itu juga dapat ditulisvoid move(int* units) { ... }
, meskipun saya lebih suka gaya sebelumnya. Anda membaca keduanya sebagai "int pointer." Lihat juga stackoverflow.com/a/8911253Jawaban:
Potongan-potongan terkecil dari bahasa C adalah token leksikal , seperti kata kunci (misalnya
int
,if
,break
), pengidentifikasi (misalnyamove
,units
) dan lain-lain.*
adalah elemen leksikal yang disebut punctuator (seperti misalnya{}()+
). Sebuah punctuator dapat memiliki arti berbeda tergantung pada bagaimana ia digunakan:Dalam C11 standar bab 6.5 pada ekspresi,
*
didefinisikan sebagai operator unary (bagian 6.5.3.2, untuk tipuan) dan sebagai operator multiplikasi (bagian 6.5.5), persis seperti yang telah Anda jelaskan. Tetapi*
hanya diartikan sebagai operator sesuai dengan aturan tata bahasa yang membuat ekspresi yang valid.Tapi ada juga bab 6.2 tentang konsep, yang menjelaskan bahwa pointer ke tipe adalah tipe turunan. Bagian 6.7.6.1 tentang deklarator pointer lebih tepat:
Ini memang membuat
*
bagian dari jenis turunan (*
berarti ada "penunjuk", tetapi selalu perlu jenis lain untuk mengatakan apa jenisnya menunjuk ke sesuatu).Catatan: Tidak ada kontradiksi dalam hal ini. Anda menggunakan elemen bahasa leksikal yang berbeda setiap hari ketika Anda berbicara bahasa Inggris: " pegangan " menunjuk sesuatu dan " menangani " berarti melakukan sesuatu, dua penggunaan tata bahasa yang sama sekali berbeda dari unsur leksikal yang sama.
sumber
Dalam C, tipuan dalam deklarasi lebih baik dibaca sebagai bagian dari variabel daripada bagian dari tipe. Jika saya punya:
pernyataan ini mungkin ditafsirkan untuk membaca: menyatakan sebuah variabel, bernama
a
, bahwa ketika dereferenced adalah tipeint
.Ini penting ketika beberapa variabel dinyatakan sekaligus:
Kedua deklarasi sama, dan keduanya
a
danb
bukan tipe yang sama -a
adalah pointer ke int danb
int. Tetapi deklarasi (2) tampak seolah-olah "tipe pointer" adalah bagian dari tipe ketika sebenarnya deklarasi*a
.sumber
Untuk menambah jawaban yang benar lainnya:
Itu hanya pernyataan deklarasi yang mencerminkan potensi ekspresi penggunaan. IIRC, kupikir Kernigan atau Ritchie menyebutnya eksperimen! Ini beberapa teks yang mendukung:
(Penekanan saya.)
http://codinghighway.com/2013/12/29/the-absolute-definitive-guide-to-decipher-c-declarations/
Jadi, ya, Anda benar, ini memang operator yang sama yang diterapkan pada ekspresi deklarasi, meskipun seperti yang Anda amati hanya beberapa operator yang masuk akal (mis. ++ tidak).
Bintang seperti itu memang bagian dari tipe variabel individual yang dideklarasikan; namun, sebagaimana dicatat oleh poster lain, poster tidak (lebih tepatnya, tidak bisa) dibawa ke variabel lain yang dideklarasikan pada waktu yang sama (yaitu dalam pernyataan deklarasi yang sama) - setiap variabel dimulai dengan jenis basis yang sama seperti target (akhirnya), dan kemudian mendapatkan penunjuk, array, dan operator fungsi (peluang untuk menerapkan atau tidak) sendiri untuk menyelesaikan tipenya.
Inilah sebabnya mengapa programmer yang berpengalaman cenderung lebih suka (1)
int *p;
vs.int* p;
dan (2) mendeklarasikan hanya satu variabel per deklarasi, meskipun bahasa lebih memungkinkan.Untuk menambahkan bahwa itu
int (*p);
adalah deklarasi hukum, orangtua ini hanya mengelompokkan dan dalam kasus sederhana ini, dan tidak melakukan apa pun yang berbedaint *p
. Ini sama dengan mengatakan ekspresi (non-deklaratif)(i) >= (0)
sama dengani >= 0
, karena Anda selalu dapat menambahkan secara legal()
.Saya menyebutkan bahwa sebagai contoh lain, meskipun, mengapa programmer lebih memilih salah satu bentuk dari yang lain, jadi pertimbangkan
int (*p);
vsint(* p);
. Mungkin Anda bisa melihat bagaimana tanda kurung, tanda bintang, dll. Berlaku untuk variabel bukan tipe dasar (yaitu dengan menambahkan semua tanda kurung yang diizinkan).sumber
Dalam deklarasi fungsi ini:
itu
*
adalah bagian dari tipe, yaituint*
. Itu bukan operator. Itulah sebabnya banyak orang menulisnya sebagai:sumber
Hanya
*
,[]
, dan()
operator memiliki makna dalam deklarasi (C ++ menambahkan&
, tapi kami tidak akan masuk ke sini).Dalam deklarasi
yang
int
-ness darip
ditentukan oleh jenis specifierint
, sedangkan pointer-nessp
ditentukan oleh deklarator*p
.The tipe dari
p
adalah "pointer keint
"; tipe ini sepenuhnya ditentukan oleh kombinasi specifier tipeint
plus deklarator*p
.Dalam deklarasi, deklarator memperkenalkan nama hal yang dideklarasikan (
p
) bersama dengan informasi tipe tambahan yang tidak diberikan oleh specifier tipe ("pointer ke"):Ini penting - pointer-ness, array-ness, dan function-ness ditentukan sebagai bagian dari deklarator, bukan tipe specifier 1 . Jika kamu menulis
itu akan diuraikan sebagai
jadi hanya
a
akan dinyatakan sebagai pointer keint
;b
danc
dinyatakan sebagaiint
s biasa .The
*
,[]
, dan()
operator dapat dikombinasikan untuk membuat jenis sewenang-wenang kompleks:Perhatikan bahwa
*
,,[]
dan()
patuhi aturan prioritas yang sama dalam deklarasi yang mereka lakukan dalam ekspresi.*a[N]
diuraikan seperti*(a[N])
dalam deklarasi dan ekspresi.Hal yang sangat penting untuk disadari dalam hal ini adalah bahwa bentuk deklarasi cocok dengan bentuk ekspresi dalam kode. Kembali ke contoh asli kami, kami memiliki pointer ke integer bernama
p
. Jika kami ingin mengambil nilai integer itu, kami menggunakan*
operator untuk dereferensip
, seperti:Jenis ungkapannya
*p
adalahint
, yang mengikuti dari deklarasiDemikian pula, jika kita memiliki array pointer
double
dan kita ingin mengambil nilai tertentu, kita indeks ke dalam array dan melakukan dereferensi hasilnya:Sekali lagi, jenis ungkapannya
*ap[i]
adalahdouble
, yang mengikuti dari deklarasiJadi mengapa tidak
++
berperan dalam deklarasi seperti*
,[]
, atau()
? Atau operator lain seperti+
atau->
atau&&
?Yah, pada dasarnya, karena definisi bahasa mengatakannya. Itu hanya mengesampingkan
*
,,[]
dan()
untuk memainkan peran apa pun dalam deklarasi, karena Anda harus dapat menentukan jenis pointer, array, dan fungsi. Tidak ada tipe "increment-this" yang terpisah, jadi tidak perlu++
menjadi bagian dari deklarasi. Tidak ada "bitwise-ini" jenis, sehingga tidak perlu untuk unary&
,|
,^
, atau~
menjadi bagian dari deklarasi baik. Untuk jenis yang menggunakan.
operator pemilihan anggota, kami menggunakanstruct
danunion
tag dalam deklarasi. Untuk jenis yang menggunakan->
operator, kami menggunakan tagstruct
danunion
bersama dengan*
operator di deklarator.*iptr
yang menentukan pointer-ness dari nama typedef.sumber
Memang benar ada dua arti bagi
*
operator . Tidak benar bahwa itu adalah satu-satunya makna*
token .Dalam deklarasi suka
yang
*
tidak operator; itu bagian dari sintaksis suatu deklarasi.Sintaks deklarasi C dimaksudkan untuk mencerminkan sintaks ekspresinya, sehingga deklarasi di atas dapat dibaca sebagai "
*p
adalah tipeint
", dari mana kita dapat menyimpulkan bahwa itup
adalah tipeint*
. Namun, ini bukan aturan yang tegas, dan itu tidak dinyatakan di manapun dalam standar. Alih-alih, sintaks deklarasi didefinisikan sendiri, secara terpisah dari sintaks ekspresi. Itulah sebabnya, misalnya, sebagian besar operator yang dapat muncul dalam ekspresi tidak dapat muncul dengan makna yang sama dalam deklarasi (kecuali jika mereka adalah bagian dari ekspresi yang merupakan bagian dari deklarasi, seperti+
operator dalamint array[2+2];
).Sebuah kasus di mana "deklarasi cermin menggunakan" prinsip tidak cukup bekerja adalah:
di mana
arr[10]
akan bertipeint
jika ada .Dan sebenarnya masih ada lagi penggunaan
*
token. Parameter array dapat dideklarasikan dengan[*]
untuk mengindikasikan array panjang variabel. (Ini ditambahkan dalam C99.) Ini*
bukan perkalian atau dereferensi. Saya menduga itu terinspirasi oleh sintaks shell wildcard.sumber
int *p = 0;
terlihat mirip dengan penggunaan * p = 0; `tetapi artinya sangat berbeda.int*
).