int main ()
{
int a = 5,b = 2;
printf("%d",a+++++b);
return 0;
}
Kode ini memberikan kesalahan berikut:
error: lvalue diperlukan sebagai operan increment
Tetapi jika saya meletakkan spasi di sepanjang a++ +
dan ++b
, maka itu berfungsi dengan baik.
int main ()
{
int a = 5,b = 2;
printf("%d",a++ + ++b);
return 0;
}
Apa arti kesalahan pada contoh pertama?
x+++++y
diuraikan sebagaix ++ ++ + y
, yang melanggar batasan pada operator kenaikan, meskipun parsex ++ + ++ y
mungkin menghasilkan ekspresi yang benar."Jawaban:
printf("%d",a+++++b);
ditafsirkan(a++)++ + b
sesuai dengan Aturan Makan Maksimal ! .++
(postfix) tidak mengevaluasi kelvalue
tetapi membutuhkan operannya menjadilvalue
.! 6.4 / 4 mengatakan token preprocessing berikutnya adalah urutan karakter terpanjang yang dapat membentuk token preprocessing "
sumber
Penyusun ditulis secara bertahap. Tahap pertama disebut lexer dan mengubah karakter menjadi struktur simbolik. Jadi "++" menjadi sesuatu seperti
enum SYMBOL_PLUSPLUS
. Kemudian, tahap pengurai mengubahnya menjadi pohon sintaksis abstrak, tetapi tidak dapat mengubah simbol. Anda dapat mempengaruhi lexer dengan menyisipkan spasi (yang mengakhiri simbol kecuali dalam tanda kutip).Lexer normal adalah greedy (dengan beberapa pengecualian), jadi kode Anda diinterpretasikan sebagai
Input ke parser adalah aliran simbol, jadi kode Anda akan menjadi seperti ini:
[ SYMBOL_NAME(name = "a"), SYMBOL_PLUS_PLUS, SYMBOL_PLUS_PLUS, SYMBOL_PLUS, SYMBOL_NAME(name = "b") ]
Yang menurut parser salah secara sintaksis. (EDIT berdasarkan komentar: Salah semantik karena Anda tidak dapat menerapkan ++ ke nilai r, yang menghasilkan ++)
adalah
Tidak apa-apa. Begitu juga contoh Anda yang lain.
sumber
a++
).a++
menghasilkan nilai r.x = 10&987&&654&&321
adalah ilegal, tetapi cukup anehx = 10&987&&654&&&321
adalah legal.Lexer menggunakan apa yang umumnya disebut algoritma "munch maksimum" untuk membuat token. Itu berarti saat membaca karakter, ia terus membaca karakter sampai menemukan sesuatu yang tidak bisa menjadi bagian dari token yang sama seperti yang sudah dimilikinya (misalnya, jika telah membaca digit jadi yang dimilikinya adalah angka, jika bertemu an
A
, ia tahu itu tidak bisa menjadi bagian dari nomor tersebut, jadi ia berhenti dan meninggalkanA
di buffer input untuk digunakan sebagai awal dari token berikutnya). Ia kemudian mengembalikan token itu ke parser.Dalam hal ini, artinya
+++++
mendapat lexed sebagaia ++ ++ + b
. Karena kenaikan pasca pertama menghasilkan nilai r, yang kedua tidak dapat diterapkan padanya, dan kompilator memberikan kesalahan.Hanya FWIW, di C ++ Anda dapat membebani
operator++
untuk menghasilkan nilai l, yang memungkinkan ini berfungsi. Sebagai contoh:struct bad_code { bad_code &operator++(int) { return *this; } int operator+(bad_code const &other) { return 1; } }; int main() { bad_code a, b; int c = a+++++b; return 0; }
Kompilasi dan berjalan (meskipun tidak melakukan apa-apa) dengan kompiler C ++ yang saya miliki (VC ++, g ++, Comeau).
sumber
16FA
adalah heksadesimal baik-baik saja jumlah yang berisi A.0x
di awal itu akan tetap memperlakukan itu sebagai16
diikuti olehFA
, bukan satu angka heksadesimal.0x
bukan bagian dari nomor tersebut.x
satu digit, sepertinya itu tidak perlu.Contoh persis ini tercakup dalam draf standar C99 ( detail yang sama di C11 ) bagian 6.4 Elemen leksikal paragraf 4 yang berbunyi:
yang juga dikenal sebagai aturan munch maksimal yang digunakan dalam analisis leksikal untuk menghindari ambiguitas dan bekerja dengan mengambil sebanyak mungkin elemen untuk membentuk token yang valid.
Paragraf ini juga memiliki dua contoh, yang kedua adalah pencocokan tepat untuk pertanyaan Anda dan adalah sebagai berikut:
yang memberitahu kita bahwa:
akan diuraikan sebagai:
yang melanggar batasan kenaikan posting karena hasil kenaikan posting pertama adalah nilai r dan kenaikan posting membutuhkan nilai l. Ini tercakup dalam bagian
6.5.2.4
operator kenaikan dan penurunan Postfix yang mengatakan ( penekanan milik saya ):dan
Buku C ++ Gotchas juga membahas kasus ini di
Gotcha #17
Maximal Munch Problems , masalah yang sama di C ++ juga dan juga memberikan beberapa contoh. Ini menjelaskan bahwa ketika berhadapan dengan kumpulan karakter berikut:penganalisis leksikal dapat melakukan salah satu dari tiga hal berikut:
-
,>
dan*
->
dan*
->*
Aturan makan maksimal memungkinkannya menghindari ambiguitas ini. Penulis menunjukkan bahwa itu ( dalam konteks C ++ ):
Contoh pertama adalah templat yang argumen templatnya juga templat ( yang diselesaikan dalam C ++ 11 ), misalnya:
list<vector<string>> lovos; // error! ^^
Yang mengartikan tanda kurung sudut penutup sebagai operator shift , dan oleh karena itu diperlukan ruang untuk menghilangkan ambiguitas:
list< vector<string> > lovos; ^
Kasus kedua melibatkan argumen default untuk pointer, misalnya:
void process( const char *= 0 ); // error! ^^
akan diartikan sebagai
*=
operator penugasan, solusi dalam hal ini adalah memberi nama parameter dalam deklarasi.sumber
>>
Aturan ditanyakan di: stackoverflow.com/questions/15785496/…Kompilator Anda berusaha keras untuk mengurai
a+++++b
, dan menafsirkannya sebagai(a++)++ +b
. Sekarang, hasil dari kenaikan pasca (a++
) bukanlah nilai l , yaitu tidak dapat ditambahkan setelah kenaikan lagi.Harap jangan pernah menulis kode seperti itu dalam program kualitas produksi. Pikirkan tentang orang malang yang mengejar Anda yang perlu menafsirkan kode Anda.
sumber
a ++ mengembalikan nilai sebelumnya, rvalue. Anda tidak dapat menaikkan ini.
sumber
Karena itu menyebabkan perilaku tidak terdefinisi.Yang mana?
Ya, baik Anda maupun kompiler tidak mengetahuinya.EDIT:
Alasan sebenarnya adalah seperti yang dikatakan oleh yang lain:
Itu ditafsirkan sebagai
(a++)++ + b
.tapi kenaikan pos membutuhkan lvalue (yang merupakan variabel dengan nama) tetapi (a ++) mengembalikan rvalue yang tidak bisa dinaikkan sehingga mengarah ke pesan kesalahan yang Anda dapatkan.
Terima kasih kepada yang lain untuk menunjukkan hal ini.
sumber
a+++b
juga selalua++ + b
a++ ++ +b
yang tidak dapat diuraikan.a+++++b
tidak mengevaluasi ke(a++)++)+b
. Tentunya dengan GCC jika Anda memasukkan tanda kurung tersebut dan membangun kembali, pesan kesalahan tidak berubah.Saya pikir kompilator melihatnya sebagai
c = ((a ++) ++) + b
++
harus memiliki nilai yang dapat dimodifikasi sebagai operan. a adalah nilai yang dapat dimodifikasi.a++
namun merupakan 'rvalue', tidak dapat dimodifikasi.By the way kesalahan saya lihat di GCC C adalah sama, tetapi berbeda-worded:
lvalue required as increment operand
.sumber
Ikuti urutan presesi ini
1. ++ (kenaikan sebelum)
2. + - (penambahan atau pengurangan)
3. "x" + "y" menambahkan kedua urutan tersebut
int a = 5,b = 2; printf("%d",a++ + ++b); //a is 5 since it is post increment b is 3 pre increment return 0; //it is 5+3=8
sumber