Các định nghĩa kỳ lạ về các macro TRUE và FALSE


300

Tôi đã thấy các định nghĩa vĩ mô sau đây trong một cuốn sách mã hóa.

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

Không có lời giải thích ở đó.

Hãy giải thích cho tôi làm thế nào những điều này sẽ làm việc như TRUEFALSE.


63
Tôi nghĩ rằng đó chỉ là một cách thú vị để định nghĩa TRUE là 1 và FALSE là 0
BlackDwarf

160
Lưu ý rằng đây là một ý tưởng khủng khiếp không có dấu ngoặc quanh các biểu thức đó. Ý tôi là đó là một ý tưởng tồi tệ với họ, nhưng không có bạn chỉ yêu cầu một đêm dài để gỡ lỗi.
TartanLlama

70
Tôi có thể biết cuốn sách mã hóa mà bạn đang tham khảo không?
artm

47
Tôi hy vọng rằng cuốn sách bao gồm điều này như một ví dụ về mã xấu hoặc cố tình che khuất.
Jon Hanna

31
@Daniel: Một ý tưởng khác là rand ()% 2 định nghĩa MAYBE là rand ()% 2, do đó, đôi khi đó là == TRUE và đôi khi == FALSE.
Kaiserludi

Câu trả lời:


380

Chúng ta hãy xem: '/' / '/'có nghĩa là nghĩa charđen /, chia cho chính charnghĩa đen '/'. Kết quả là một, mà âm thanh hợp lý cho TRUE.

'-' - '-'có nghĩa là nghĩa charđen '-', trừ đi từ chính nó. Đây là số không ( FALSE).

Có hai vấn đề với điều này: thứ nhất, nó không thể đọc được. Sử dụng 10hoàn toàn tốt hơn. Ngoài ra, như TartanLlama và KerrekSB đã chỉ ra, nếu bạn định sử dụng định nghĩa đó, vui lòng thêm dấu ngoặc đơn xung quanh chúng để bạn không gặp phải bất ngờ nào:

#include <stdio.h>

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

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

Điều này sẽ in giá trị của charchữ '-'(45 trên hệ thống của tôi).

Với dấu ngoặc đơn:

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

chương trình in chính xác bằng 0, mặc dù không có ý nghĩa gì khi nhân giá trị thật với số nguyên, nhưng đó chỉ là một ví dụ về loại lỗi không mong muốn có thể cắn bạn nếu bạn không nuôi dưỡng macro của mình.


6
Chết tiệt, tôi đã mất rất nhiều để hiểu nó: thậm chí còn nghĩ rằng đó là một điều kỳ lạ vì glyphs ... không biết xD
Luis Masuelli

8
Nó thực sự có ý nghĩa để nhân lên với giá trị thật. Đối với thụt đầu dòng * nên_indent sẽ dẫn đến 0 hoặc thụt đầu dòng dựa trên việc nên_indent mà không phân nhánh. (Tôi đoán rằng đây là ví dụ tồi, khi làm việc với phân nhánh đơn văn bản không thành vấn đề, (Tôi đã thấy kỹ thuật này trong shader và trong XPATH (cả hai quá khác nhau và tôi không nhớ chính xác mẫu))
Alpedar

2
Alpedar - nhưng về mặt khái niệm và giao phối không tạo ra cảm giác để làm như vậy - trong trường hợp này sẽ rõ ràng hơn (và về mặt khái niệm) để sử dụng ifthay vì nhân TRUEvới một số nguyên.
Jay

4
Giải thích tuyệt vời. Có huy hiệu vàng!
Michael Hampton

2
Phủ định logic có thể được thực hiện notx = TRUE- x;và hoạt động tốt. Ngoại trừ đó TRUE-FALSElà -44 (giả sử ASCII)
Hagen von Eitzen

89

Nó chỉ là một cách viết khác

#define TRUE 1
#define FALSE 0

Biểu thức '/'/'/'sẽ chia giá trị char của '/'chính nó, kết quả sẽ cho 1.

Biểu thức '-'-'-'sẽ trừ đi giá trị char của '-'chính nó, kết quả sẽ cho 0.

Các dấu ngoặc xung quanh toàn bộ definebiểu thức bị thiếu, điều này có thể dẫn đến lỗi trong mã khi sử dụng các macro này. Câu trả lời của Jay khá tốt.

Một ví dụ về kịch bản "đời thực" trong đó việc quên dấu ngoặc có thể gây hại là việc sử dụng kết hợp các macro này với toán tử truyền kiểu C. boolVí dụ, nếu ai đó quyết định chuyển các biểu thức này sang 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;
}

Đây là những gì chúng ta nhận được:

True: 0
False: -44

Vì vậy, (bool) TRUEsẽ thực sự đánh giá false(bool) FALSEsẽ đánh giá true.


4
Ví dụ này là một ví dụ hay :)
Kit Fisto

44

Nó tương đương với văn bản

#define TRUE 1
#define FALSE 0

Những gì biểu thức '/'/'/'thực sự làm là chia nhân vật /(bất kể giá trị số của nó là gì), vì vậy nó trở thành 1.

Tương tự, biểu thức '-'-'-'trừ nhân vật -khỏi chính nó và ước lượng 0.

Nó sẽ tốt hơn để viết

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

để tránh sự thay đổi ngẫu nhiên của các giá trị khi được sử dụng với các toán tử ưu tiên cao hơn khác.


5
CƯỜI LỚN! Đó là lý do tại sao các macro nên được ngoặc đơn.
0605002

3 quyền trên một quả cầu và bạn kết thúc ở cùng một nơi
Derek 會 5/12/15

@KerrekSB Không, nhưng ba người làm được :)
Tim Long

33

Jay đã trả lời tại sao các giá trị của các biểu thức này là 01.

Vì lợi ích lịch sử, những biểu hiện này '/'/'/''-'-'-'đến từ một trong những mục của Cuộc thi mã C bị xáo trộn quốc tế lần thứ nhất năm 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);}

(Liên kết đến chương trình tại đây , có một gợi ý về những gì chương trình này làm trong trang IOCCC ở trên.)

Ngoài ra, nếu tôi nhớ chính xác các biểu thức này như các macro bị che khuất TRUEFALSEcũng được bao gồm trong cuốn sách "Obfuscated C và Other Mysteries" của Don Libes (1993).


7

Đó là cách vui nhộn để viết macro cho TrueFalse.

Như nhiều lời giải thích đã được cung cấp /phương tiện một số 1 byte (theo ASCII) khi chia cho bản thân nó cung cấp cho bạn 1sẽ được điều trị như Truevà tương tự -một lần nữa một số byte khi trừ giá trị như nhau nó cung cấp cho bạn 0đó sẽ được hiểu làfalse

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

do đó chúng tôi có thể thay thế /hoặc -bằng bất kỳ char nào chúng tôi muốn, ví dụ:

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

Sẽ giữ nguyên ý nghĩa như biểu thức ban đầu.


6

Hãy bắt đầu với sự thật. Bạn có thể đọc nó dưới dạng '/' / '/', có nghĩa là "ký tự '/' chia cho ký tự '/'". Vì mỗi ký tự, trong C, là một giá trị số (trên một byte), nên có thể được đọc là "giá trị ASCII của ký tự '/' chia cho giá trị ASCII của cùng một ký tự", có nghĩa là 1 (vì rõ ràng, x / x là 1). Do đó, TRUElà 1.

FALSE, cùng một lý do: '-'-'-'đọc '-' - '-', tức là "giá trị ASCII của '-' trừ đi giá trị ASCII của '-'", bằng 0. Do đó, FALSElà 0.

Đây là một cách khó chịu để nêu rõ ràng.


7
Điều này không liên quan gì đến ASCII.
Kerrek SB

6
@Fabien: Nó không phụ thuộc vào ASCII. '/'/'/'là 1 cho bất kỳ bộ ký tự hợp lệ nào , cho dù '/' == 47(như trong ASCII) hoặc '/' == 97(như trong EBCDIC) hoặc bất kỳ giá trị nào khác.
Keith Thompson

4
@Pawel: Việc triển khai C tuân thủ không thể ánh xạ '/'tới 0. Giá trị đó được dành riêng cho ký tự null.
Keith Thompson

2
Bạn đang bị phạm tội.
Matheus208

3
@ Matheus208 Nếu Pawel là người phạm tội, thì đó là ('-'-'-') vì quan điểm của anh ta dựa trên một điều kiện không có căn cứ; mô tả nhận xét của Keith là pedantic có thể nhiều hơn ('/' / '/') nhưng tôi gọi chúng là "làm rõ" (và với mặt cười được thêm vào "pedantic" dường như '/' - '/' đối với tôi). Có thể ('-' / '-') rằng các bình luận được ghép lại có thể được gọi là phạm vi nhưng, 1) không phải là điều gì đó bắt buộc trong lĩnh vực này? 2) họ làm tôi suy nghĩ; và 3) Tôi rõ ràng hơn một số điều so với tôi. Và vâng, tôi đoán bản thân mình là người phạm tội! (Nhưng tôi rõ ràng hơn về "pedantic" nghĩa là gì so với tôi! ;-)
Zhora 4/12/2015
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.