Definisi-definisi aneh dari macro TRUE dan FALSE

300

Saya telah melihat definisi makro berikut dalam buku kode.

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

Tidak ada penjelasan di sana.

Tolong jelaskan kepada saya bagaimana ini akan berfungsi sebagai TRUEdan FALSE.

Keshava GN
sumber
63
Saya pikir ini hanya cara lucu untuk mendefinisikan BENAR sebagai 1 dan SALAH sebagai 0
BlackDwarf
160
Perhatikan bahwa ini adalah ide yang buruk tanpa tanda kurung di sekitar ekspresi itu. Maksud saya itu adalah ide yang buruk bagi mereka, tetapi tanpa Anda hanya meminta malam panjang debugging.
TartanLlama
70
Bolehkah saya tahu buku kode yang Anda referensikan?
artm
47
Saya harap buku itu memasukkan ini sebagai contoh kode yang buruk atau sengaja dikaburkan.
Jon Hanna
31
@Aniel: Gagasan lain adalah rand ()% 2 mendefinisikan MAYBE sebagai rand ()% 2, sehingga kadang-kadang == BENAR dan kadang-kadang == SALAH.
Kaiserludi

Jawaban:

380

Mari kita lihat: '/' / '/'berarti yang charliteral /, dibagi dengan charliteral '/'itu sendiri. Hasilnya adalah satu, yang kedengarannya masuk akal TRUE.

Dan '-' - '-'artinya charsecara literal '-', dikurangkan dari dirinya sendiri. Ini nol (FALSE ).

Ada dua masalah dengan ini: pertama, itu tidak dapat dibaca. Menggunakan 1dan 0benar-benar lebih baik. Juga, seperti yang ditunjukkan oleh TartanLlama dan KerrekSB, jika Anda akan menggunakan definisi itu, silakan tambahkan tanda kurung di sekitar mereka sehingga Anda tidak akan memiliki kejutan:

#include <stdio.h>

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

int main() {
        printf ("%d\n", 2 * FALSE);
        return 0;
}

Ini akan mencetak nilai charliteral'-' (45 pada sistem saya).

Dengan tanda kurung:

#define TRUE  ('/'/'/')
#define FALSE ('-'-'-')

program dengan benar mencetak nol, meskipun tidak masuk akal untuk melipatgandakan nilai kebenaran dengan bilangan bulat, tetapi itu hanyalah contoh dari jenis bug yang tidak terduga yang dapat menggigit Anda jika Anda tidak mengurung makro Anda.

Jay
sumber
6
Sialan aku butuh banyak untuk memahaminya: bahkan berpikir itu adalah hal yang aneh seperti mesin terbang ... tidak tahu xD
Luis Masuelli
8
Sebenarnya masuk akal untuk berkembang biak dengan nilai kebenaran. Untuk memeriksa indentasi * should_indent akan menghasilkan 0 atau indentasi berdasarkan apakah should_indent tanpa bercabang. (Saya kira ini adalah contoh yang buruk, ketika bekerja dengan text single branching tidak masalah, (saya telah melihat teknik ini di shader dan di XPATH (keduanya terlalu berbeda dan saya tidak ingat bentuk persisnya))
Alpedar
2
Alpedar - tetapi secara konseptual dan matehmatis tidak masuk akal untuk melakukannya - dalam hal ini akan lebih jelas (dan secara konseptual masuk akal) untuk menggunakan ifalih - alih mengalikan TRUEdengan integer.
Jay
4
Penjelasan yang bagus. Punya lencana emas!
Michael Hampton
2
Negasi logis dapat diimplementasikan notx = TRUE- x;dan berfungsi dengan baik. Kecuali itu TRUE-FALSE-44 (dengan asumsi ASCII)
Hagen von Eitzen
89

Ini hanyalah cara penulisan lainnya

#define TRUE 1
#define FALSE 0

Ekspresi '/'/'/'akan membagi nilai char '/'dengan sendirinya, yang akan memberikan 1 sebagai hasilnya.

Ekspresi '-'-'-'akan mengurangi nilai char '-'dari itu sendiri, yang akan menghasilkan 0 sebagai hasilnya.

Tanda kurung di sekitar seluruh defineekspresi tidak ada, yang dapat menyebabkan kesalahan dalam kode menggunakan makro ini. Jawaban Jay mendukungnya.

Contoh skenario "kehidupan nyata" di mana melupakan tanda kurung dapat berbahaya adalah penggunaan gabungan makro ini dengan operator pemain gaya-C. Jika seseorang memutuskan untuk memberikan ekspresi ini ke booldalam C ++ misalnya:

#include <iostream>

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

int main() {
    std::cout << "True: " << (bool) TRUE << std::endl;
    std::cout << "False: " << (bool) FALSE << std::endl;
    return 0;
}

Inilah yang kami dapatkan:

True: 0
False: -44

Jadi (bool) TRUEakan benar-benar mengevaluasi false, dan (bool) FALSEakan mengevaluasi true.

BlackDwarf
sumber
4
Contohnya bagus sekali :)
Kit Fisto
44

Itu sama dengan menulis

#define TRUE 1
#define FALSE 0

Apa ekspresi '/'/'/'sebenarnya adalah membagi karakter /(apa pun nilai numeriknya) dengan sendirinya, sehingga menjadi 1.

Demikian pula, ekspresi '-'-'-'mengurangi karakter -dari dirinya sendiri dan mengevaluasi ke0 .

Akan lebih baik menulis

#define TRUE ('/'/'/')
#define FALSE ('-'-'-')

untuk menghindari perubahan nilai yang tidak disengaja ketika digunakan dengan operator dengan prioritas lebih tinggi lainnya.

0605002
sumber
5
LOL! Itu sebabnya makro harus dikurung dengan benar.
0605002
3 hak bola dan Anda berakhir di tempat yang sama
Derek 朕 會 功夫
@ GerrekSB Tidak, tetapi tiga kiri lakukan :)
Tim Long
33

Jay sudah menjawab mengapa nilai dari ekspresi ini adalah 0dan 1.

Demi sejarah, ungkapan-ungkapan ini '/'/'/'dan '-'-'-'berasal dari salah satu entri dari Kontes Kode C Internasional I yang Dikurangi pada tahun 1984 :

int i;main(){for(;i["]<i;++i){--i;}"];read('-'-'-',i+++"hell\
o, world!\n",'/'/'/'));}read(j,i,p){write(j/p+p,i---j,i/i);}

(Tautan ke program di sini , ada petunjuk tentang apa yang dilakukan program ini di halaman IOCCC di atas.)

Juga jika saya ingat dengan benar ungkapan-ungkapan ini sebagai makro yang dikaburkan untuk TRUEdan FALSEjuga tercakup dalam buku "Misterius C dan Misteri Lain" oleh Don Libes (1993).

ouah
sumber
7

Ini cara lucu untuk menulis makro untuk Truedan False.

Karena banyak penjelasan yang telah diberikan /berarti angka 1 byte (sesuai ASCII) ketika dibagi dengan sendirinya memberi Anda 1yang akan diperlakukan sebagai Truedan juga -lagi nomor byte ketika dikurangi nilai yang sama itu memberi Anda 0yang akan ditafsirkan sebagaifalse

#define TRUE  '/'/'/'
#define FALSE '-'-'-'

maka kita dapat mengganti /atau -dengan char apa pun yang kita suka, misalnya:

#define TRUE  '!'/'!'
#define FALSE 'o'-'o'

Akan tetap memiliki makna yang sama dengan ungkapan asli.

anand
sumber
6

Mari kita mulai dengan yang benar. Anda dapat membacanya sebagai '/' / '/', yang berarti "karakter '/' dibagi dengan karakter '/'". Karena setiap karakter, dalam C, adalah nilai numerik (pada satu byte), itu dapat dibaca sebagai "nilai ASCII dari karakter '/' dibagi dengan nilai ASCII dari karakter yang sama", yang berarti 1 (karena, jelas, x / x adalah 1). Karenanya, TRUEadalah 1.

Sebab FALSE, alasannya sama: '-'-'-'berbunyi '-' - '-', yaitu "nilai ASCII dari '-' dikurangi nilai ASCII dari '-'", yang adalah 0. Oleh karena itu, FALSEadalah 0.

Ini adalah cara jahat untuk menyatakan yang sudah jelas.

Fabien
sumber
7
Ini tidak ada hubungannya dengan ASCII.
Kerrek SB
6
@Fabien: Tidak tergantung pada ASCII. '/'/'/'adalah 1 untuk setiap set karakter yang valid, apakah '/' == 47(seperti dalam ASCII), atau '/' == 97(seperti dalam EBCDIC), atau nilai lainnya.
Keith Thompson
4
@ Pamel: Implementasi C yang sesuai tidak dapat dipetakan '/'ke 0. Nilai itu dicadangkan untuk karakter nol.
Keith Thompson
2
Anda menjadi pedantic.
Matheus208
3
@ Matheus208 Jika Pawel menjadi orang yang bertele-tele, maka itu ('-'-'-') karena maksudnya didasarkan pada kondisi yang tidak disebutkan; menggambarkan pernyataan Keith sebagai bertele-tele mungkin lebih ('/' / '/') tapi saya akan menyebutnya "klarifikasi" (dan dengan menambahkan smiley "bertele-tele" jelas tampak '/' - '/' bagi saya). Mungkin ('-' / '-') bahwa komentar yang diambil bersama-sama dapat disebut pedantic tetapi, 1) bukankah itu agak wajib dalam bidang ini? 2) mereka membuat saya berpikir; dan 3) Saya sedikit lebih jelas dalam beberapa hal daripada saya. Dan ya, saya kira saya sendiri terlalu jago! (Tapi saya lebih jelas tentang apa yang "pedantic" berarti daripada saya! ;-)
Zhora