Mengapa ukuran suatu fungsi dalam C selalu 1 byte?

87

Ketika kami memeriksa ukuran fungsi menggunakan sizeof(), kami selalu mendapatkan 1 byte . Apa yang dimaksud dengan 1 byte ini?

pengguna1645461
sumber

Jawaban:

80

Ini adalah pelanggaran batasan, dan kompilator Anda harus mendiagnosisnya. Jika mengkompilasinya terlepas dari itu, program Anda memiliki perilaku yang tidak terdefinisi [terima kasih kepada @Steve Jessop untuk klarifikasi mode kegagalan, dan lihat jawaban @Michael Burr untuk mengapa beberapa kompiler mengizinkan ini]: Dari C11, 6.5.3.4./ 1:

The sizeofOperator tidak akan diterapkan pada ekspresi yang memiliki jenis fungsi

Kerrek SB
sumber
11
Itu kendala, yang berarti dalam kompiler yang sesuai itu didiagnosis. Jika kompilator tetap mengkompilasinya (setelah mendiagnosisnya), maka perilaku tidak ditentukan. Jika kompilator tidak mendiagnosisnya (yang misalnya gcc tidak tanpa -pedantic), Anda memiliki kompilator yang tidak sesuai dan setiap program memiliki perilaku yang tidak ditentukan.
Steve Jessop
1
Perilaku tersebut menempatkannya dalam kategori yang sama dengan ekstensi GNU C, tetapi saya tidak tahu mengapa ada orang yang menginginkan perilaku tersebut, jadi saya tidak tahu mengapa penulis GNU berusaha keras untuk menambahkannya.
Steve Jessop
1
@SteveJessop: Perhatikan bahwa ini bahkan dengan -std=c11, bukan gnu11 . Ini adalah ekstensi kompiler yang sangat aneh.
Kerrek SB
6
Ooh! Saya yakin itu untuk mengaktifkan aritmatika pada fungsi pointer, dengan cara yang sama yaitu sizeof(void)1 di GNU C.
Steve Jessop
3
Mengenai -std=c11: seseorang harus merujuk -std=c*opsi ke Standar Periklanan. Mereka tidak mengaktifkan mode kesesuaian, mereka hanya menonaktifkan ekstensi yang akan mencegah program yang terbentuk dengan baik dari kompilasi (seperti typeofmenjadi kata kunci, karena program C yang terbentuk dengan baik dapat menggunakannya sebagai nama variabel, tetapi gccsecara default akan menolaknya. ). Selain itu, untuk menonaktifkan ekstensi yang memungkinkan program yang rusak lolos tidak terdiagnosis, Anda memerlukan -pedanticatau -pedantic-errors.
Steve Jessop
56

Ini bukan perilaku tidak terdefinisi - standar bahasa C memerlukan diagnostik saat menggunakan sizeofoperator dengan penunjuk fungsi (nama fungsi) karena ini merupakan pelanggaran batasan untuksizeof operator.

Namun, sebagai ekstensi ke bahasa C, GCC memungkinkan aritmatika pada voidpointer dan pointer fungsi, yang dilakukan dengan memperlakukan ukuran a voidatau fungsi sebagai 1. Akibatnya, sizeofoperator akan mengevaluasi ke 1untuk voidatau fungsi dengan GCC. Lihat http://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html#Pointer-Arith

Anda bisa membuat GCC mengeluarkan peringatan saat menggunakan sizeofdengan operand ini dengan menggunakan opsi -pedanticatau -Wpointer-arithke GCC. Atau buat kesalahan dengan -Werror=pointer-arith.

Michael Burr
sumber
Logika Anda salah. C membutuhkan pesan diagnostik untuk beberapa, tetapi tidak semua UB. Anda tidak dapat menyatakan bahwa sesuatu telah menentukan perilaku hanya karena ada diagnosisnya.
MSalters
4
C memerlukan diagnostik untuk semua pelanggaran batasan (5.1.1.3 Diagnostik di C99 atau C11). Batasan (3.8 di C99 / C11) adalah "batasan, baik sintaksis atau semantik, yang dengannya eksposisi elemen bahasa akan diinterpretasikan", yang sepertinya mengatakan bahwa sesuatu yang tidak mengikuti batasan tidak dapat diinterpretasikan .
Michael Burr
3
Dan untuk memperjelas - pelanggaran batasan tidak menghasilkan perilaku yang tidak ditentukan. Ini adalah kesalahan, seperti kesalahan sintaksis. Misalnya, standar mengatakan, "jika persyaratan" harus "atau" tidak boleh "yang muncul di luar batasan dilanggar, perilaku tidak ditentukan". Jika pelanggaran batasan akan mengakibatkan UB, mengapa standar berbicara tentang "shalls" dan "tidak boleh" yang tidak menjadi kendala di sini?
Michael Burr
3
Saya sebenarnya tidak banyak menyebutkan apa-apa tentang UB kecuali sizeoffungsinya bukan UB (yang saya sebutkan cukup banyak hanya karena jawaban lain menyatakan itu UB). Tapi mungkin saya mengacaukannya karena cara saya menyusun kalimat. Agar lebih jelas. sizeoffungsi bukan UB (seperti yang diklaim beberapa jawaban). Ini adalah pelanggaran batasan. Oleh karena itu, diperlukan diagnosis. GCC mengizinkannya sebagai ekstensi.
Michael Burr
2
@KerrekSB: OP tidak mendapatkan diagnostik karena mungkin mereka menggunakan GCC, yang mengizinkan penggunaan ini sebagai ekstensi bahasa C.
Michael Burr
13

Ini menandakan bahwa penulis penyusun memutuskan nilai 1 daripada membuat setan terbang dari hidung Anda (memang, itu adalah penggunaan lain yang tidak ditentukan sizeofyang memberi kita ungkapan: "kompiler C itu sendiri HARUS mengeluarkan diagnostik JIKA ini yang pertama diperlukan diagnostik yang dihasilkan dari program Anda, dan kemudian MUNGKIN itu sendiri menyebabkan setan terbang dari hidung Anda (yang, omong-omong, bisa menjadi pesan diagnostik yang terdokumentasi) sama seperti MUNGKIN mengeluarkan diagnostik lebih lanjut untuk pelanggaran lebih lanjut terhadap aturan atau batasan sintaksis (atau, dalam hal ini, untuk alasan apa pun yang dipilihnya). " https://groups.google.com/forum/?fromgroups=#!msg/comp.std.c/ycpVKxTZkgw/S2hHdTbv4d8J

Dari sini ada istilah gaul "setan hidung" untuk apa pun yang diputuskan oleh penyusun untuk dilakukan sebagai respons terhadap konstruksi yang tidak ditentukan. 1adalah setan hidung dari penyusun ini untuk kasus ini.

Jon Hanna
sumber
@IlmariKaronen Namun, saya harus mengakui, bahwa ada alasan mengapa sebagian besar jawaban saya di C (dan C ++) ada pada prinsip bahasa-agnostik umum atau nugget historis seperti itu. Pengalaman C saya berbatasan dengan sejarah itu sendiri :)
Jon Hanna
7

Seperti yang ditunjukkan orang lain, sizeof () dapat mengambil pengenal yang valid, tetapi itu tidak akan mengembalikan hasil yang valid (jujur ​​benar dan valid) untuk nama fungsi. Selain itu, hal itu pasti mungkin, atau mungkin tidak, mengakibatkan sindrom "setan keluar dari hidung".

Jika Anda ingin membuat profil ukuran fungsi program Anda, periksa peta linker, yang dapat ditemukan di direktori hasil menengah (tempat hal-hal dikompilasi ke dalam .obj / .o atau tempat gambar / file yang dapat dieksekusi diletakkan). Kadang-kadang ada opsi untuk membuat atau tidak file peta ini ... itu bergantung pada compiler / linker.

Jika Anda menginginkan ukuran pointer ke suatu fungsi, semuanya berukuran sama, ukuran kata pengalamatan di cpu Anda.

jpinto3912
sumber
1
Pernyataan macam apa itu "pasti mungkin atau mungkin tidak" ??? Bukankah itu benar tentang segalanya?
Kerrek SB
@KerrekSB ya, tapi di sini mungkin atau mungkin tidak melakukan apa-apa, dan masih dalam aturan. Memang benar kompilator mungkin atau mungkin tidak menolak untuk dikompilasi int x = 1;tetapi hanya satu dari yang diizinkan untuk kompilator yang memenuhi standar. Dengan sizeof()diterapkan ke suatu fungsi, itu mungkin atau mungkin tidak mengembalikan nilai yang ditetapkan, atau menolak untuk dikompilasi, atau mengembalikan nilai acak berdasarkan apa pun yang ada di register tertentu pada saat itu. Setan hidung harfiah tidak mungkin, tetapi dalam huruf standar.
Jon Hanna
@kerrek Ini mungkin benar untuk apa-apa atau mungkin tidak salah untuk apa pun ... melihatnya sebagai tidak logis.
jpinto3912
1
Jika Anda ingin mengetahui ukuran penunjuk ke suatu fungsi, terapkan sizeofke penunjuk ke suatu fungsi.
alexis