Diberikan oleh seorang rekan sebagai teka-teki, saya tidak tahu bagaimana sebenarnya program C ini mengkompilasi dan berjalan. Apa >>>=
operator ini dan 1P1
literal aneh ? Saya telah menguji di dentang dan GCC. Tidak ada peringatan dan hasilnya "???"
#include <stdio.h>
int main()
{
int a[2]={ 10, 1 };
while( a[ 0xFULL?'\0':-1:>>>=a<:!!0X.1P1 ] )
printf("?");
return 0;
}
0x.1P1
adalah heksadesimal literal dengan eksponen. Ini0x.1
adalah nomor bagian, atau 1/16 di sini. Angka setelah 'P' adalah kekuatan dua angka dikalikan dengan. Begitu0x.1p1
juga 1/16 * 2, atau 1/8. Dan jika Anda bertanya-tanya tentang0xFULL
itu saja0xF
, danULL
merupakan akhiran untukunsigned long long
Jawaban:
Garis:
berisi digraf
:>
dan<:
, yang diterjemahkan ke]
dan[
masing - masing, sehingga setara dengan:Secara literal
0xFULL
sama dengan0xF
(yang merupakan hex untuk15
); yangULL
hanya menetapkan bahwa itu adalahunsigned long long
literal . Bagaimanapun, sebagai boolean itu benar, maka0xFULL ? '\0' : -1
dievaluasi menjadi'\0'
, yang merupakan karakter literal yang nilai numeriknya sederhana0
.Sementara itu,
0X.1P1
adalah floating point heksadesimal literal sama untuk 2/16 = 0,125. Bagaimanapun, menjadi non-nol, itu juga benar sebagai boolean, jadi meniadakannya dua kali dengan!!
menghasilkan lagi1
. Dengan demikian, semuanya disederhanakan menjadi:Operator
>>=
adalah penugasan majemuk yang menggeser operan kirinya ke kanan dengan jumlah bit yang diberikan oleh operan kanan, dan mengembalikan hasilnya. Dalam hal ini, operan yang tepata[1]
selalu memiliki nilai1
, sehingga setara dengan:atau, yang setara:
Nilai awal
a[0]
adalah 10. Setelah bergeser ke kanan sekali, itu menjadi 5, lalu (pembulatan ke bawah) 2, lalu 1 dan akhirnya 0, di mana titik loop berakhir. Jadi, loop body dieksekusi tiga kali.sumber
P
dalam0X.1P1
.e
dalam10e5
, kecuali Anda harus menggunakanp
untuk heksadesimal literal karenae
merupakan digit heksadesimal.p
memisahkan mantissa dan eksponen, seperti halnyae
notasi float ilmiah normal; satu perbedaan adalah bahwa, dengan hex floats, basis dari bagian eksponensial adalah 2 bukannya 10, jadi0x0.1p1
sama dengan 0x0.1 = 1/16 kali 2¹ = 2. (Dalam hal apa pun, tidak ada yang penting di sini; tidak nol nilai akan bekerja sama baiknya di sana.)char
literal", dan menambahkan tautan Wikipedia. Terima kasih!Ini adalah beberapa kode yang agak kabur yang melibatkan digraf , yaitu
<:
dan:>
yang merupakan token alternatif untuk[
dan]
masing - masing. Ada juga beberapa penggunaan operator kondisional . Ada juga operator yang sedikit bergeser , penugasan shift yang tepat>>=
.Ini adalah versi yang lebih mudah dibaca:
dan versi yang lebih mudah dibaca, menggantikan ekspresi dalam
[]
untuk nilai-nilai yang mereka tetapkan untuk:Mengganti
a[0]
dana[1]
untuk nilainya harus membuatnya mudah untuk mengetahui apa yang dilakukan loop, yaitu setara dengan:yang hanya melakukan pembagian (integer) oleh 2 di setiap iterasi, menghasilkan urutan
5, 2, 1
.sumber
????
, alih-alih???
seperti yang didapat OP? (Huh.) Codepad.org/nDkxGUNi memang menghasilkan???
.Mari kita lihat ungkapan dari kiri ke kanan:
Hal pertama yang saya perhatikan adalah bahwa kami menggunakan operator ternary dari penggunaan
?
. Jadi subekspresi:mengatakan "jika
0xFULL
bukan nol, kembali'\0'
, jika tidak-1
.0xFULL
adalah heksadesimal heksadesimal dengan akhiran panjang-panjang unsigned - yang berarti itu adalah heksadesimal harafiah jenisunsigned long long
. Itu tidak terlalu penting, karena0xF
dapat masuk ke dalam bilangan bulat biasa.Juga, operator ternary mengubah jenis istilah kedua dan ketiga menjadi jenis umum mereka.
'\0'
kemudian dikonversi menjadiint
, yang adil0
.Nilai
0xF
jauh lebih besar dari nol, sehingga melewati. Ekspresi sekarang menjadi:Selanjutnya,
:>
adalah digraf . Ini adalah konstruksi yang diperluas ke]
:>>=
adalah operator shift kanan yang telah ditandatangani, kita dapat mengaturnyaa
agar lebih jelas.Selain itu,
<:
adalah digraf yang diperluas ke[
:0X.1P1
adalah heksadesimal literal dengan eksponen. Tapi tidak peduli nilainya,!!
apa pun yang bukan nol itu benar.0X.1P1
adalah0.125
yang bukan nol, sehingga menjadi:The
>>=
merupakan operator pergeseran kanan ditandatangani. Ini mengubah nilai operan kirinya dengan menggeser bitnya ke depan dengan nilai di sisi kanan operator.10
dalam biner adalah1010
. Jadi, inilah langkah-langkahnya:>>=
mengembalikan hasil operasinya, sehingga selama pergeserana[0]
tetap tidak nol untuk setiap kali bitnya bergeser tepat satu, loop akan terus berlanjut. Upaya keempat adalah di manaa[0]
menjadi0
, sehingga loop tidak pernah dimasukkan.Hasilnya,
?
dicetak tiga kali.sumber
:>
adalah digraf , bukan trigraph. Ini tidak ditangani oleh preprocessor, itu hanya diakui sebagai token yang setara]
.?:
) memiliki tipe yang merupakan tipe umum dari suku kedua dan ketiga. Istilah pertama selalu bersyarat dan memiliki tipebool
. Karena kedua istilah ketiga dan ketiga telah mengetikint
hasil operasi ternary akanint
, tidakunsigned long long
.#
dan##
memiliki bentuk digraf; tidak ada yang menghentikan implementasi dari menerjemahkan digraf ke non-digraf selama fase terjemahan awal