Apa fungsinya ??! ??! operator lakukan di C?

1990

Saya melihat garis C yang tampak seperti ini:

!ErrorHasOccured() ??!??! HandleError();

Itu dikompilasi dengan benar dan tampaknya berjalan ok. Sepertinya memeriksa apakah ada kesalahan, dan jika ada, itu menanganinya. Tetapi saya tidak begitu yakin apa yang sebenarnya dilakukan atau bagaimana melakukannya. Tampaknya programmer mencoba mengekspresikan perasaan mereka tentang kesalahan.

Saya belum pernah melihat ??!??!sebelumnya dalam bahasa pemrograman apa pun, dan saya tidak dapat menemukan dokumentasi untuk itu di mana pun. (Google tidak membantu dengan istilah pencarian seperti ??!??!). Apa fungsinya dan bagaimana contoh kode bekerja?

Peter Olson
sumber
44
@PeterOlson, bagaimana Anda berharap !ErrorHasOccurred() ??!???! HandleError();untuk mengkompilasi? Itu ??! ??? !. Buktikan intinya?
CVn
31
Saya sarankan Anda membaca kode bersih. ErrorHasOccured () harus di refactored ke ErrorHasNotOccured () sehingga membersihkan tanda seru ... siapa yang punya waktu untuk memahami semua operator ini ??!
KadekM
17
Saya lebih suka ErrorHasOccured() && HandleError()diri saya sendiri. Itu juga bagaimana Lua melakukannya.
Hugo Zink
76
@ KadekM, memindahkan negasi ke nama fungsi tidak membuat kode bersih, melainkan sebaliknya.
marcelm
14
Catatan untuk siapa saja yang berakhir di sini setelah bertarung sampai mati dengan mesin pencari mereka: SymbolHound dapat membantu pencarian simbolik.
Jakob

Jawaban:

1579

??!adalah trigraph yang diterjemahkan menjadi |. Jadi katanya:

!ErrorHasOccured() || HandleError();

yang, karena hubungan arus pendek, setara dengan:

if (ErrorHasOccured())
    HandleError();

Guru Minggu Ini (berurusan dengan C ++ tetapi relevan di sini), tempat saya mengambilnya.

Kemungkinan asal trigraph atau seperti @DwB tunjukkan dalam komentar itu lebih mungkin karena EBCDIC menjadi sulit (lagi). Ini diskusi di papan IBM developerWorks tampaknya mendukung teori itu.

Dari ISO / IEC 9899: 1999 §5.2.1.1, catatan kaki 12 (h / t @ Random832):

Urutan trigraph memungkinkan input karakter yang tidak didefinisikan dalam Set Kode Invarian seperti yang dijelaskan dalam ISO / IEC 646, yang merupakan subset dari set kode ASCII tujuh bit AS.

pengguna786653
sumber
378
Trigraphs awalnya diperlukan jika Anda tidak memiliki keyboard mis. '|' simbol. Ini dia entah itu programmer yang sengaja menyebalkan atau editor 'fitur' aneh
Martin Beckett
36
Ya, itu setara dengan if (ErrorHasOccured()) HandleError(). Untungnya Anda biasanya hanya menemukan idiom ini dalam kode perl.
user786653
22
Ini belum tentu EBCDIC - himpunan karakter yang membutuhkan trigraph hampir persis sama dengan himpunan karakter yang tidak berubah-ubah dalam ISO-646 (yaitu standar 'ascii nasional' yang lama).
Random832
52
Alternatif yang bisa dibaca dengan sempurna ErrorHasOccurred() && HandleError();adalah Yaitu, jika Anda terbiasa dengan shell scripting. :)
Yam Marcovic
18
Baca sebagai "Either no ErrorHasOcurred atau Anda harus HandleError", @SparkyRobinson.
Omar Antolín-Camarena
453

Nah, mengapa ini ada secara umum mungkin berbeda dari mengapa itu ada dalam contoh Anda.

Semuanya dimulai setengah abad yang lalu dengan repurposing terminal komunikasi hardcopy sebagai antarmuka pengguna komputer. Pada era awal Unix dan C itu adalah ASR-33 Teletype.

Perangkat ini lambat (10 cps) dan berisik dan jelek dan pandangannya tentang set karakter ASCII berakhir pada 0x5f, jadi itu (perhatikan gambar) tidak ada tombol:

{ | } ~ 

Trigraphs didefinisikan untuk memperbaiki masalah tertentu. Idenya adalah bahwa program C dapat menggunakan subset ASCII yang ditemukan pada ASR-33 dan di lingkungan lain kehilangan nilai ASCII yang tinggi.

Contoh Anda sebenarnya dua ??!, masing-masing makna |, jadi hasilnya ||.

Namun, orang yang menulis kode C hampir secara definisi memiliki peralatan modern, 1 jadi dugaan saya adalah: seseorang memamerkan atau menghibur diri mereka sendiri, meninggalkan semacam telur Paskah dalam kode untuk Anda temukan.

Itu pasti berhasil, itu mengarah ke pertanyaan SO sangat populer.

ASR-33 Teletype

                                            ASR-33 Teletype


1. Dalam hal ini, trigraph ditemukan oleh komite ANSI, yang pertama kali bertemu setelah C menjadi sukses besar, sehingga tidak ada kode C atau coders asli yang akan menggunakannya.

DigitalRoss
sumber
18
Ini bukan satu-satunya kasus karakter yang hilang, di keyboard dan set karakter. Commodore 64 kemungkinan akan lebih akrab bagi banyak orang di akhir usia tiga puluhan dan ke atas - set karakter yang ditampilkan keduanya tidak memiliki kawat gigi (dan mungkin juga bar dan tilde) - dalam hal ini karena "ASCII" bukan ASCII . Dalam ECMA-6 (hampir selalu disebut ASCII, tetapi bukan AS-ASCII) ada 18 kode khusus kawasan, tapi saya tidak tahu kode mana itu. Satu hal yang bisa saya katakan dengan pasti - di Inggris "ASCII", #diganti dengan £. Di wilayah lain, mungkin "ASCII" tidak punya kawat gigi, dll.
Steve314
7
Karakter ATASCII yang mirip dengan komputer Atari 8-bit juga tidak memiliki {} dan ~ dan `.
dan04
42
Lihat ini dua artikel Wikipedia. Saya baru saja cukup umur untuk mengingat era 7-bit charset nasional (walaupun saya yakin mereka masih tertinggal di beberapa sudut gelap yang tidak tersapu), dan buku yang pertama kali saya pelajari dari saya merasa perlu untuk memperingatkan tentang kemungkinan if (x || y) { a[i] = '\0'; }terlihat seperti if (x öö y) ä aÄiÅ = 'Ö0'; ådi charset yang salah.
Ilmari Karonen
9
Catatan sejarah lain yang menarik adalah bahwa Unix (yang merupakan platform besar yang digunakan C) mungkin merupakan sistem pertama yang memiliki signifikansi (dan mungkin keseluruhan pertama) untuk nilai-nilai alfabet standar untuk huruf kecil daripada huruf besar. Walaupun saya belum melihat banyak sistem kontemporer dengan mata saya sendiri, saya pikir ini adalah tanda kecanggihan yang nyata. Selain benar-benar satu-satunya OS yang layak, Unix juga mengubah huruf besar Anda menjadi lebih rendah, dan bukan sebaliknya. Orang-orang itu sangat keren.
DigitalRoss
16
Cerita lucu yang harus saya ceritakan ... kompiler XL Fortran workstation IBM RS / 6000 dikembangkan dari kompiler XL C. Dalam beberapa rilis pertama, mereka secara tidak sengaja pergi dalam pemrosesan trigraph, jadi ada beberapa urutan karakter Fortran yang sah (dalam string literal, IIRC) yang disalahartikan sebagai trigraph C, yang mengarah ke beberapa bug yang menarik!
Phil Perry
166

Ini adalah C trigraph . ??!adalah |, begitu ??!??!juga operator||

Joel Falcou
sumber
5
trigraph berasal dari periode di mana beberapa keyboard tidak memiliki semua tombol yang mereka miliki sekarang. Itu juga membantu ketika beberapa editor teks disediakan karakter khusus untuk hal-hal khusus. Ini sebagian besar adalah peninggalan masa lalu dan enabler quizz;)
Joel Falcou
5
Karena beberapa keyboard tampaknya tidak memiliki "|" sehingga beberapa orang tidak memiliki pilihan selain menekan keyboard berulang kali sampai terjadi trigraph yang memberi mereka simbol yang mereka butuhkan.
Burung hantu
Dan kemudian ada <iso646.h>file header.
David R Tribble
149

Seperti yang sudah dinyatakan ??!??!pada dasarnya adalah dua trigraph ( ??!dan ??!lagi) disatukan yang diganti-diterjemahkan menjadi ||, yaitu logika OR , oleh preprocessor.

Tabel berikut ini berisi setiap trigraph akan membantu menyatukan kombinasi trigraph alternatif:

Trigraph   Replaces

??(        [
??)        ]
??<        {
??>        }
??/        \
??'        ^
??=        #
??!        |
??-        ~

Sumber: C: A Reference Manual Edisi ke-5

Jadi sebuah trigraph yang kelihatannya ??(??)pada akhirnya akan dipetakan ke [], ??(??)??(??)akan digantikan oleh [][]dan seterusnya, Anda mendapatkan idenya.

Karena trigraph diganti selama preprocessing, Anda dapat menggunakan cppuntuk melihat sendiri hasilnya, menggunakan trigr.cprogram konyol :

void main(){ const char *s = "??!??!"; } 

dan memprosesnya dengan:

cpp -trigraphs trigr.c 

Anda akan mendapatkan output konsol sebesar

void main(){ const char *s = "||"; }

Seperti yang dapat Anda perhatikan, opsi -trigraphsharus ditentukan atau yang lain cppakan mengeluarkan peringatan; ini menunjukkan caranya trigraph adalah sesuatu dari masa lalu dan tidak memiliki nilai modern selain membingungkan orang yang mungkin menabrak mereka .


Adapun alasan di balik pengenalan trigraph, lebih baik dipahami ketika melihat bagian sejarah ISO / IEC 646 :

ISO / IEC 646 dan pendahulunya ASCII (ANSI X3.4) sebagian besar mendukung praktik yang ada mengenai pengkodean karakter dalam industri telekomunikasi.

Karena ASCII tidak menyediakan sejumlah karakter yang diperlukan untuk bahasa selain bahasa Inggris, sejumlah varian nasional dibuat yang menggantikan beberapa karakter yang kurang digunakan dengan yang dibutuhkan .

(penekanan milikku)

Jadi, pada dasarnya, beberapa karakter yang diperlukan (yang ada trigraph ada) diganti dalam varian nasional tertentu. Ini mengarah pada representasi alternatif menggunakan trigraph yang terdiri dari karakter yang masih dimiliki oleh varian lain.

Dimitris Fasarakis Hilliard
sumber