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ư TRUE
và FALSE
.
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ư TRUE
và FALSE
.
Câu trả lời:
Chúng ta hãy xem: '/' / '/'
có nghĩa là nghĩa char
đen /
, chia cho chính char
nghĩa đen '/'
. Kết quả là một, mà âm thanh hợp lý cho TRUE
.
Và '-' - '-'
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 1
và 0
hoà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 char
chữ '-'
(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.
if
thay vì nhân TRUE
với một số nguyên.
notx = TRUE- x;
và hoạt động tốt. Ngoại trừ đó TRUE-FALSE
là -44 (giả sử ASCII)
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ộ define
biể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. bool
Ví 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) TRUE
sẽ thực sự đánh giá false
và (bool) FALSE
sẽ đánh giá true
.
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.
Jay đã trả lời tại sao các giá trị của các biểu thức này là 0
và 1
.
Vì lợi ích lịch sử, những biểu hiện này '/'/'/'
và '-'-'-'
đế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 TRUE
và FALSE
cũng được bao gồm trong cuốn sách "Obfuscated C và Other Mysteries" của Don Libes (1993).
Đó là cách vui nhộn để viết macro cho True
và False
.
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 1
sẽ được điều trị như True
và 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.
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 đó, TRUE
là 1.
Vì 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 đó, FALSE
là 0.
Đây là một cách khó chịu để nêu rõ ràng.
'/'/'/'
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.
'/'
tới 0
. Giá trị đó được dành riêng cho ký tự null.