Mengapa sizeof int salah, sedangkan sizeof (int) benar?

97

Kita tahu itu sizeofadalah operator yang digunakan untuk menghitung ukuran tipe data dan ekspresi apa pun, dan ketika operan adalah ekspresi, tanda kurung dapat dihilangkan.

int main()
{
        int a;

        sizeof int;
        sizeof( int );
        sizeof a;
        sizeof( a );

        return 0;
}

penggunaan pertama sizeofsalah, sementara yang lain benar.

Ketika dikompilasi menggunakan gcc, pesan kesalahan berikut akan diberikan:

main.c:5:9: error: expected expression before int

Pertanyaan saya adalah mengapa standar C tidak mengizinkan operasi semacam ini. Akan sizeof intmenyebabkan ambiguitas?

Yishu Fang
sumber
5
Lucunya, tidak semua ekspresi diterima tanpa tanda kurung: coba sizeof (int)a.
Fred Foo
2
@MikkelK .: OP menanyakan alasan dibalik kutipan standar dia sudah mengetahui kutipan yang disebutkan dalam jawaban yang ditandai.
Alok Save
2
@ Lundin: sizeof +(int)amemiliki keunggulan dibandingkan *&benar-benar menyusun ;-)
Steve Jessop
2
@SteveJessop Ah benar, itu bukan lvalue. Meskipun itu terkompilasi di Embarcadero C ++, anehnya. Bagaimanapun, saya yakin kita baru saja menemukan kegunaan untuk operator + unary! Itu pasti pertama kalinya dalam sejarah pemrograman C :)
Lundin
2
@ Lundin: Anda masih harus berhati-hati dengan unary +. Misalnya, sizeof +(char)a == sizeof(int)karena promosi integer, kemungkinan kesalahan tidak terlalu besar hanya dengan memasukkan tanda kurung jika ada kekhawatiran sama sekali tentang ekspresi yang Anda coba ukur. Jadi saya tidak yakin saya akan menyebutnya "penggunaan", meskipun saya akui saya memang menggunakannya ...
Steve Jessop

Jawaban:

101

Berikut ini bisa jadi ambigu:

sizeof int * + 1

Apakah itu (sizeof (int*)) + 1, atau (sizeof(int)) * (+1)?

Jelas bahasa C bisa memperkenalkan aturan untuk menyelesaikan ambiguitas, tapi saya bisa membayangkan mengapa itu tidak mengganggu. Dengan bahasa yang ada, penentu tipe tidak pernah muncul "telanjang" dalam ekspresi, sehingga tidak perlu aturan untuk menentukan apakah detik *itu bagian dari tipe atau operator aritmatika.

Tata bahasa yang ada sudah menyelesaikan potensi ambiguitas sizeof (int *) + 1. Hal ini (sizeof(int*))+1, tidak sizeof((int*)(+1)) .

C ++ memiliki masalah yang agak mirip untuk diselesaikan dengan sintaks cor gaya fungsi. Anda bisa menulis int(0)dan Anda bisa menulis typedef int *intptr; intptr(0);, tetapi Anda tidak bisa menulis int*(0). Dalam kasus tersebut, resolusinya adalah bahwa jenis "polos" harus berupa nama jenis yang sederhana, tidak boleh sembarang jenis id lama yang mungkin memiliki spasi di dalamnya, atau tanda baca di belakangnya. Mungkin sizeofbisa saja didefinisikan dengan batasan yang sama, saya tidak yakin.

Steve Jessop
sumber
1
C ++ memiliki new int*(X)yang akan menjadi ambigu jika C ++ tidak menentukan bahwa operator baru mengambil string terpanjang yang mungkin bisa menjadi tipe. Jadi di C ++ mereka bisa membuat yang sama dengan sizeof, saya rasa. Tetapi di C ++ Anda dapat mengatakan sizeof int()yang kemudian akan menjadi ambigu (tipe atau nilai diinisialisasi int?).
Johannes Schaub - litb
@ JohannesSchaub-litb: Mmm, jadi mungkin C ++ dapat mengatakan bahwa tipe tersebut lebih disukai jika memungkinkan untuk mengurai, jika tidak, itu adalah ekspresi. Ambiguitas akan terselesaikan tetapi sizeof int()akan berbentuk buruk ("tidak operator()untuk size_t"), yang saya perkirakan tidak akan disukai!
Steve Jessop
32

Dari C99 Standard

6.5.3.4.2
The sizeofOperator menghasilkan ukuran (dalam bytes) dari operan, yang mungkin merupakan ekspresi atau nama kurung dari tipe.

Dalam kasus Anda, intada ekspresi atau nama dalam tanda kurung.

Jainendra
sumber
10
Saya tidak mengerti mengapa ini mendapat 7 suara positif. Seperti tiga jawaban yang dihapus, ini hanya mengulangi aturan tersebut alih-alih menjelaskan mengapa aturan itu ada.
Fred Foo
8
@larsmans, ya, saya setuju dengan Anda. Meski terus mengulang aturan, tapi setidaknya, itu memberi sedikit otorisasi membaca.
Yishu Fang
3
@larsmans Jika kami mulai mencoba membenarkan setiap keputusan yang dibuat di C99, kami akan berada di sini sepanjang tahun. Mengutip standar adalah cara terbaik untuk mengakhiri diskusi ini.
Perry
1
@Perry: jika Anda tidak menyukai pertanyaan semacam ini, Anda dapat memilih untuk menutup pertanyaan sebagai argumentatif.
Fred Foo
4
Sebagai non-praktisi C ++, meskipun saya mengerti jawaban ini, tidak yakin apa masalahnya jika Anda bisa membaca dan memahami bahasa Inggris.
Kev
6

Ada dua cara untuk menggunakan operator sizeof di C. Sintaksnya adalah ini:

C11 6.5.3 Unary operators
...
sizeof unary-expression
sizeof ( type-name )

Setiap kali Anda menggunakan tipe sebagai operand, Anda harus memiliki tanda kurung, dengan definisi sintaks bahasa. Jika Anda menggunakan sizeof pada ekspresi, Anda tidak memerlukan tanda kurung.

Standar C memberikan satu contoh di mana Anda mungkin ingin menggunakannya pada ekspresi:

sizeof array / sizeof array[0]

Namun, demi konsistensi, dan untuk menghindari bug yang terkait dengan prioritas operator, saya secara pribadi menyarankan untuk selalu menggunakan () apa pun situasinya.

Lundin
sumber
@ JohannesSchaub-litb Saya setuju bahwa itu tidak memberikan alasan apa pun tentang bagaimana komite standar C beralasan ketika mereka menentukan standar C90. Anda harus bertanya kepada mereka ... Itu menjawab tanpa alasan yang diberikan, namun, C tidak mengizinkannya karena sintaksnya seperti yang ditentukan di 6.5.3. OP juga sepertinya tidak menyadari perbedaan antara sizeof expressiondan sizeof(type), yang dijelaskan dalam jawaban ini.
Lundin
(Sebagai catatan, saya baru saja membaca alasan C90 dan C11 dan tidak memberikan penjelasan apa pun.)
Lundin
Saya menduga tidak ada alasan yang diperlukan untuk itu, ini hanya cara desainer asli C memutuskan untuk melakukannya. Mungkin itu mempermudah pengurai awal. Saya akan memposting jawaban tentang fakta bahwa typedefs dan variabel berbagi namespace yang sama, tetapi itu tidak menghalangi sintaks pertama; itu hanya perlu aturan parsing untuk mengatakan bahwa ia lebih memilih variabel ketika tidak ada tanda kurung, lebih memilih tipe jika ada, dan bentuk mana pun dapat digunakan ketika namanya tidak ambigu. Karena tidak perlu mengubahnya, komite standar membiarkannya.
Barmar