นิยามแปลก ๆ ของมาโคร TRUE และ FALSE


300

ฉันได้เห็นคำจำกัดความของแมโครดังต่อไปนี้ในหนังสือการเข้ารหัส

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

ไม่มีคำอธิบายที่นั่น

กรุณาอธิบายให้ฉันวิธีการเหล่านี้จะทำงานเป็นและTRUEFALSE


63
ฉันคิดว่ามันเป็นวิธีที่ตลกที่จะกำหนด TRUE เป็น 1 และ FALSE เป็น 0
BlackDwarf

160
โปรดทราบว่านี่เป็นความคิดที่แย่มากหากไม่มีวงเล็บล้อมรอบสำนวนเหล่านั้น ฉันหมายความว่ามันเป็นความคิดที่น่ากลัวกับพวกเขา แต่โดยที่คุณกำลังเพียงการขอคืนที่ยาวนานของการแก้จุดบกพร่อง
TartanLlama

70
ฉันขอทราบหนังสือรหัสที่คุณกำลังอ้างอิงได้หรือไม่
artm

47
ฉันหวังว่าหนังสือเล่มนี้รวมเป็นตัวอย่างของรหัสที่ไม่ดีหรือไม่ชัดเจนโดยเจตนา
Jon Hanna

31
@Daniel: แนวคิดอื่นคือการแรนด์ ()% 2 กำหนด MAYBE เป็นแรนด์ ()% 2 ดังนั้นบางครั้งก็เป็น == TRUE และบางครั้ง == FALSE
Kaiserludi

คำตอบ:


380

ลองมาดูกัน: '/' / '/'หมายถึงcharตัวอักษร/หารด้วยcharอักษร'/'ตัวเอง TRUEผลที่ได้คือหนึ่งซึ่งเสียงที่เหมาะสมสำหรับ

และ'-' - '-'หมายถึงcharตัวอักษร'-'ลบออกจากตัวเอง นี่คือศูนย์ ( FALSE)

ปัญหานี้มีอยู่สองประการ: อันดับแรกไม่สามารถอ่านได้ การใช้งาน1และ0ดีกว่าอย่างแน่นอน นอกจากนี้เนื่องจาก TartanLlama และ KerrekSB ได้ชี้ให้เห็นว่าหากคุณจะใช้คำจำกัดความดังกล่าวโปรดเพิ่มวงเล็บไว้รอบ ๆ เพื่อที่คุณจะได้ไม่ต้องประหลาดใจ:

#include <stdio.h>

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

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

นี่จะพิมพ์ค่าของcharตัวอักษร'-'(45 บนระบบของฉัน)

ด้วยวงเล็บ:

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

โปรแกรมพิมพ์เลขศูนย์อย่างถูกต้องแม้ว่ามันจะไม่สมเหตุสมผลที่จะคูณค่าความจริงด้วยจำนวนเต็ม แต่มันก็เป็นเพียงตัวอย่างของข้อผิดพลาดที่ไม่คาดคิดชนิดหนึ่งที่สามารถกัดคุณได้หากคุณไม่ได้วงเล็บมาโครของคุณ


6
ประณามฉันใช้เวลามากในการทำความเข้าใจ: s แม้คิดว่ามันเป็นสิ่งที่แปลกประหลาดในฐานะร่ายมนตร์ ... ไม่ทราบ xD
Luis Masuelli

8
มันสมเหตุสมผลแล้วที่จะคูณกับความจริง สำหรับการเยื้องการเยื้อง * should_indent จะทำให้ 0 หรือเยื้องขึ้นอยู่กับว่า should_indent โดยไม่ต้องแยก (ฉันเดาว่านี่เป็นตัวอย่างที่ไม่ดีเมื่อทำงานกับการแยกย่อยข้อความเดี่ยวไม่สำคัญ (ฉันเคยเห็นเทคนิคนี้ในเฉดสีและใน XPATH (ทั้งสองแตกต่างกันเกินไปและฉันไม่จำรูปแบบที่แน่นอน))
Alpedar

2
Alpedar - แต่มันไม่ได้มีแนวคิดและ matehmatically ทำให้ senso ทำเช่นนั้น - ในกรณีนี้มันจะชัดเจนขึ้น (และมีแนวคิดที่สมเหตุสมผล) เพื่อใช้ifแทนการคูณTRUEด้วยจำนวนเต็ม
Jay

4
คำอธิบายที่ดี มีเหรียญทอง!
Michael Hampton

2
การปฏิเสธแบบลอจิคัลอาจถูกนำมาใช้ในฐานะnotx = TRUE- x;และทำงานได้ดี ยกเว้นว่าTRUE-FALSEเป็น -44 (สมมติว่า ASCII)
Hagen von Eitzen

89

มันเป็นอีกวิธีหนึ่งในการเขียน

#define TRUE 1
#define FALSE 0

การแสดงออก'/'/'/'จะแบ่งค่าถ่านของ'/'ตัวเองซึ่งจะให้ 1 เป็นผล

การแสดงออก'-'-'-'จะลดค่าถ่านของ'-'ตัวเองซึ่งจะทำให้ 0 เป็นผล

เครื่องหมายวงเล็บทั่วทั้งdefineนิพจน์หายไปซึ่งอาจทำให้เกิดข้อผิดพลาดในรหัสโดยใช้มาโครเหล่านี้ คำตอบของเจย์นั้นค่อนข้างดี

ตัวอย่างของสถานการณ์ "ชีวิตจริง" ที่การลืมวงเล็บอาจเป็นอันตรายคือการใช้มาโครเหล่านี้ร่วมกับตัวดำเนินการส่งแบบ C หากมีคนตัดสินใจที่จะแปลงการแสดงออกเหล่านี้boolใน C ++ เช่น:

#include <iostream>

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

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

นี่คือสิ่งที่เราได้รับ:

True: 0
False: -44

ดังนั้น(bool) TRUEจริงจะประเมินfalseและจะประเมินการ(bool) FALSEtrue


4
ตัวอย่างเป็นสิ่งที่ดี :)
Kit Fisto

44

มันเทียบเท่ากับการเขียน

#define TRUE 1
#define FALSE 0

สิ่งที่แสดงออก'/'/'/'ไม่จริงคือการแบ่งตัวละคร/(สิ่งที่ค่าตัวเลขที่เป็น) 1ด้วยตัวเองดังนั้นมันจะกลายเป็น

ในทำนองเดียวกันการแสดงออก'-'-'-'ลบตัวอักษรจากตัวเองและประเมินผลการ-0

มันจะดีกว่าที่จะเขียน

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

เพื่อหลีกเลี่ยงการเปลี่ยนแปลงค่าโดยไม่ตั้งใจเมื่อใช้กับตัวดำเนินการลำดับความสำคัญสูงกว่าอื่น ๆ


5
ฮ่า ๆ! นั่นเป็นสาเหตุว่าทำไมมาโครควรถูกวงเล็บอย่างถูกต้อง
0605002

3 สิทธิ์ในทรงกลมและคุณจะอยู่ในที่เดียวกัน
Derek 朕會功夫

@KerrekSB ไม่ แต่มีสามระดับที่ทำได้ :)
Tim Long

33

เจย์ตอบแล้วว่าทำไมค่าของการแสดงออกเหล่านี้และ0 1

เพื่อประโยชน์ทางประวัติศาสตร์การแสดงออกเหล่านี้'/'/'/'และ'-'-'-'มาจากหนึ่งในรายการการประกวด C Code นานาชาติครั้งที่ 1 ในปี 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);}

(ลิงก์ไปยังโปรแกรมที่นี่มีคำใบ้ว่าโปรแกรมนี้ทำอะไรในหน้า IOCCC ด้านบน)

นอกจากนี้หากฉันจำได้อย่างถูกต้องว่านิพจน์เหล่านี้เป็นมาโครที่ทำให้ยุ่งเหยิงสำหรับTRUEและFALSEยังถูกกล่าวถึงในหนังสือ"Obfuscated C และ Mysteries อื่น ๆ "โดย Don Libes (1993)


7

มันเป็นอย่างเฮฮาสำหรับการเขียนแมโครสำหรับและTrueFalse

เนื่องจากมีการให้คำอธิบายมากมาย/หมายถึง 1 ไบต์ (ตาม ASCII) เมื่อหารด้วยตัวมันเองก็จะให้คุณ1ซึ่งจะได้รับการปฏิบัติเช่นTrueเดียวกันและก็ -เป็นจำนวนไบต์อีกครั้งเมื่อลบค่าเดียวกันที่ให้คุณ0ซึ่งจะถูกตีความว่าเป็นfalse

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

ดังนั้นเราสามารถแทนที่/หรือ-ด้วยตัวอักษรใด ๆ ที่เราต้องการตัวอย่างเช่น:

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

จะรักษาความหมายเช่นเดียวกับการแสดงออกเดิม


6

เริ่มจากความจริงกันก่อน คุณสามารถอ่านได้'/' / '/'ซึ่งหมายถึง "ตัวอักษร '/' หารด้วยตัวอักษร '/'" เนื่องจากอักขระแต่ละตัวใน C เป็นค่าตัวเลข (หนึ่งไบต์) จึงสามารถอ่านได้ว่า "ค่า ASCII ของอักขระ '/' หารด้วยค่า ASCII ของอักขระเดียวกันนั้น" ซึ่งหมายถึง 1 (เพราะเห็นได้ชัดว่า x / x คือ 1) ดังนั้นTRUEคือ 1

สำหรับFALSEเหตุผลเดียวกัน: '-'-'-'อ่าน'-' - '-'คือ "ค่า ASCII ของ '-' ลบค่า ASCII ของ '-'" ซึ่งคือ 0 ดังนั้นจึงFALSEเป็น 0

นี่เป็นวิธีที่น่ารังเกียจในการระบุอย่างชัดเจน


7
สิ่งนี้ไม่เกี่ยวข้องกับ ASCII
Kerrek SB

6
@Fabien: มันไม่ได้ขึ้นกับ ASCII '/'/'/'เป็น 1 สำหรับใด ๆชุดตัวอักษรที่ถูกต้องไม่ว่าจะเป็น'/' == 47(เป็นอยู่ใน ASCII) หรือ'/' == 97(มันเป็นใน EBCDIC) หรือค่าอื่น ๆ
Keith Thompson เมื่อ

4
@Pawel: การดำเนินงานตามนโยบาย C ไม่สามารถ map เพื่อ'/' 0ค่านั้นสงวนไว้สำหรับตัวอักษร Null
Keith Thompson

2
คุณกำลังอวดรู้
Matheus208

3
@ Matheus208 ถ้า Pawel เป็นคนเชื่องช้านั่นคือ ('-'-'-') เนื่องจากประเด็นของเขาขึ้นอยู่กับสภาพที่ไม่ได้ระบุ การอธิบายคำพูดของ Keith ว่าอวดความรู้อาจจะมากกว่า ('/' / '/') แต่ฉันเรียกพวกเขาว่า อาจเป็น ('-' / '-') ที่ความคิดเห็นที่นำมารวมกันสามารถเรียกได้ว่าอวดความรู้ แต่ 1) มันไม่ได้เป็นข้อผูกมัดในสาขานี้ 2) พวกเขาทำให้ฉันคิดว่า; และ 3) ฉันเห็นอะไรบางอย่างชัดเจนกว่าฉัน และใช่ฉันเดาว่าฉันเป็นคนพูดคล่องตัวเอง! (แต่ฉันชัดเจนเกี่ยวกับความหมายของ "pedantic" มากกว่าที่ฉันเป็น! ;-)
Zhora
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.