Ada beberapa bagian yang memungkinkan semua kombinasi operator ini bekerja dengan cara yang sama.
Alasan mendasar mengapa semua pekerjaan ini adalah bahwa suatu fungsi (seperti foo
) secara implisit dapat dikonversi menjadi pointer ke fungsi tersebut. Inilah sebabnya mengapa void (*p1_foo)() = foo;
berfungsi: foo
secara implisit dikonversi menjadi pointer ke dirinya sendiri dan pointer yang ditugaskan p1_foo
.
Unary &
, ketika diterapkan pada suatu fungsi, menghasilkan pointer ke fungsi, sama seperti itu menghasilkan alamat suatu objek ketika diterapkan pada suatu objek. Untuk pointer ke fungsi biasa, selalu redundan karena konversi fungsi-ke-fungsi-pointer implisit. Bagaimanapun, ini sebabnya void (*p3_foo)() = &foo;
bekerja.
Unary *
, ketika diterapkan pada pointer fungsi, menghasilkan fungsi menunjuk-ke, sama seperti itu menghasilkan objek menunjuk-ke ketika itu diterapkan pada pointer biasa ke objek.
Aturan-aturan ini bisa digabungkan. Pertimbangkan contoh kedua hingga terakhir Anda **foo
:
- Pertama,
foo
secara implisit dikonversi menjadi pointer ke dirinya sendiri dan yang pertama *
diterapkan ke pointer fungsi itu, menghasilkan fungsi foo
lagi.
- Kemudian, hasilnya secara implisit dikonversi menjadi pointer ke dirinya sendiri dan yang kedua
*
diterapkan, lagi-lagi menghasilkan fungsi foo
.
- Itu kemudian secara implisit dikonversi ke fungsi pointer lagi dan ditugaskan ke variabel.
Anda dapat menambahkan sebanyak yang *
Anda suka, hasilnya selalu sama. Semakin banyak *
, semakin meriah.
Kami juga dapat mempertimbangkan contoh kelima Anda &*foo
:
- Pertama,
foo
secara implisit dikonversi menjadi pointer ke dirinya sendiri; unary *
diterapkan, menghasilkan foo
lagi.
- Kemudian,
&
diterapkan ke foo
, menghasilkan pointer ke foo
, yang ditugaskan ke variabel.
Namun, &
hanya dapat diterapkan ke fungsi, bukan ke fungsi yang telah dikonversi ke pointer fungsi (kecuali, tentu saja, pointer fungsi adalah variabel, dalam hal ini hasilnya adalah pointer-to-a-pointer- to-a-function; misalnya, Anda dapat menambahkan ke daftar Anda void (**pp_foo)() = &p7_foo;
).
Inilah sebabnya mengapa &&foo
tidak berfungsi: &foo
bukan fungsi; itu adalah pointer fungsi yang merupakan nilai. Namun, &*&*&*&*&*&*foo
akan berfungsi, seperti yang akan terjadi &******&foo
, karena dalam kedua ekspresi &
itu selalu diterapkan pada fungsi dan bukan ke pointer fungsi nilai.
Perhatikan juga bahwa Anda tidak perlu menggunakan unary *
untuk melakukan panggilan melalui penunjuk fungsi; keduanya (*p1_foo)();
dan (p1_foo)();
memiliki hasil yang sama, sekali lagi karena konversi fungsi-ke-fungsi-pointer.
&foo
mengambil alamatfoo
, yang menghasilkan pointer fungsi menunjukfoo
, seperti yang diharapkan.&
operator untuk objek: diberikanint p;
,&p
menghasilkan pointer kep
dan merupakan ekspresi nilai; yang&
Operator membutuhkan ekspresi lvalue.*
, semakin kurang riang .&*
membatalkan (6.5.3.2):"The unary & operator yields the address of its operand."
/ - /"If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue."
.Saya pikir itu juga membantu untuk mengingat bahwa C hanyalah sebuah abstraksi untuk mesin yang mendasarinya dan ini adalah salah satu tempat di mana abstraksi itu bocor.
Dari perspektif komputer, fungsi hanyalah alamat memori yang, jika dijalankan, melakukan instruksi lainnya. Jadi fungsi dalam C itu sendiri dimodelkan sebagai alamat, yang mungkin mengarah ke desain yang fungsinya "sama" dengan alamat yang ditunjuknya.
sumber
&
dan*
operasi idempoten pada simbol dinyatakan sebagai fungsi dalam C yang berartifunc == *func == &func == *&func
dan karenanya*func == **func
Ini berarti bahwa jenisnya
int ()
sama denganint (*)()
sebagai parameter fungsi dan fungsi yang didefinisikan dapat diteruskan sebagai*func
,func
atau&func
.(&func)()
sama denganfunc()
. Tautan Godbolt.Suatu fungsi benar-benar sebuah alamat, oleh karena itu
*
dan&
tidak memiliki makna, dan alih-alih menghasilkan kesalahan, kompiler memilih untuk menafsirkannya sebagai alamat func.&
pada simbol yang dideklarasikan sebagai fungsi pointer namun akan mendapatkan alamat dari pointer (karena sekarang memiliki tujuan terpisah), sedangkanfuncp
dan*funcp
akan identiksumber