Cái gì ??! ??! Toán tử làm trong C?


1990

Tôi thấy một dòng C trông như thế này:

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

Nó biên dịch chính xác và dường như chạy ok. Có vẻ như nó đang kiểm tra xem có lỗi xảy ra hay không và nếu có, nó sẽ xử lý. Nhưng tôi không thực sự chắc chắn những gì nó thực sự làm hoặc làm thế nào nó làm điều đó. Có vẻ như các lập trình viên đang cố gắng bày tỏ cảm xúc của họ về lỗi.

Tôi chưa bao giờ thấy ??!??!trước đây trong bất kỳ ngôn ngữ lập trình nào và tôi không thể tìm thấy tài liệu cho nó ở bất cứ đâu. (Google không trợ giúp với các cụm từ tìm kiếm như ??!??!). Nó làm gì và làm thế nào để mẫu mã hoạt động?


44
@PeterOlson, bạn mong !ErrorHasOccurred() ??!???! HandleError();muốn biên dịch như thế nào? Đó là ??! ??? !. Chứng minh quan điểm?
một CVn

31
Tôi đề nghị bạn đọc lên mã sạch. ErrorHasOccured () nên được cấu trúc lại thành ErrorHasNotOccured () để xóa dấu chấm than ... ai có thời gian để hiểu tất cả các toán tử này ??!
KadekM

17
Tôi thích ErrorHasOccured() && HandleError()bản thân mình hơn. Đó cũng là cách Lua làm điều đó.
Hugo Zink

76
@KadekM, di chuyển phủ định vào tên hàm không tạo ra mã sạch, mà ngược lại.
marcelm

14
Một lưu ý cho bất kỳ ai kết thúc ở đây sau một cuộc chiến đến chết với công cụ tìm kiếm của họ: SymbolHound có thể giúp tìm kiếm biểu tượng.
Jakob

Câu trả lời:


1579

??!là một tr tr dịch mà dịch |. Vì vậy, nó nói:

!ErrorHasOccured() || HandleError();

trong đó, do ngắn mạch, tương đương với:

if (ErrorHasOccured())
    HandleError();

Chuyên gia của tuần (giao dịch với C ++ nhưng có liên quan ở đây), nơi tôi đã chọn cái này.

Nguồn gốc có thể của các bức thư hoặc như @DwB chỉ ra trong các bình luận, nhiều khả năng là do EBCDIC gặp khó khăn (một lần nữa). Cuộc thảo luận này trên diễn đàn nhà phát triển của IBM dường như ủng hộ lý thuyết đó.

Từ ISO / IEC 9899: 1999 §5.2.1.1, chú thích 12 (h / t @ Random832):

Trình tự bộ ba cho phép nhập vào các ký tự không được xác định trong Bộ mã bất biến như được mô tả trong ISO / IEC 646, là một tập hợp con của bộ mã ASCII bảy bit của Hoa Kỳ.


378
Các chữ cái ban đầu là cần thiết trong trường hợp bàn phím của bạn không có, ví dụ như '|' Biểu tượng. Ở đây, hoặc là lập trình viên cố tình gây phiền nhiễu hoặc một số tính năng kỳ lạ của 'biên tập viên'
Martin Beckett

36
Vâng, nó tương đương với if (ErrorHasOccured()) HandleError(). Rất may, bạn thường chỉ gặp thành ngữ này trong mã perl.
dùng786653

22
Đó không nhất thiết là EBCDIC - tập hợp các ký tự yêu cầu các bộ ba gần như khớp chính xác với tập hợp các ký tự không bất biến trong ISO-646 (tức là các tiêu chuẩn 'ascii quốc gia cũ).
Random832

52
Một sự thay thế hoàn toàn dễ đọc sẽ là ErrorHasOccurred() && HandleError();Đó là, nếu bạn đã quen với shell scripting. :)
Yam Marcovic

18
Đọc nó dưới dạng "Không có ErrorHasOcaded hoặc bạn phải Xử lýError", @SparkyRobinson.
Omar Antolín-Camarena

453

Chà, tại sao điều này tồn tại nói chung có lẽ khác với lý do tại sao nó tồn tại trong ví dụ của bạn.

Tất cả bắt đầu từ nửa thế kỷ trước với việc tái sử dụng các thiết bị đầu cuối truyền thông bản cứng như giao diện người dùng máy tính. Trong kỷ nguyên Unix và C ban đầu, đó là ASR-33 Teletype.

Thiết bị này chậm (10 cps) và ồn ào và xấu xí và chế độ xem bộ ký tự ASCII của nó kết thúc ở 0x5f, do đó, nó không có (nhìn kỹ vào pic) không có phím nào:

{ | } ~ 

Các bộ ba được xác định để khắc phục một vấn đề cụ thể. Ý tưởng là các chương trình C có thể sử dụng tập hợp con ASCII được tìm thấy trên ASR-33 và trong các môi trường khác thiếu các giá trị ASCII cao.

Ví dụ của bạn thực sự là hai trong số ??!, mỗi ý nghĩa |, vì vậy kết quả là ||.

Tuy nhiên, người viết code C gần như theo định nghĩa có thiết bị hiện đại, 1 nên tôi đoán là: một ai đó khoe khoang hay gây cười themself, để lại một loại trứng Phục sinh trong mã để bạn có thể tìm thấy.

Nó chắc chắn làm việc, nó dẫn đến một câu hỏi SO rất phổ biến.

ASR-33 Teletype

                                            ASR-33 Teletype


1. Đối với vấn đề đó, các bộ ba được phát minh bởi ủy ban ANSI, lần đầu tiên gặp sau khi C trở thành một thành công lớn, do đó, không ai trong số các mã hoặc mã C ban đầu sẽ sử dụng chúng.


18
Đây không phải là trường hợp duy nhất của các ký tự bị thiếu, trong bàn phím và bộ ký tự. Hàng hóa 64 dường như quen thuộc hơn với nhiều người ở độ tuổi ba mươi trở lên - nhân vật được hiển thị cả hai đều thiếu niềng răng (và có lẽ cả thanh và dấu ngã) - trong trường hợp này vì "ASCII" không phải là ASCII . Trong ECMA-6 (hầu như luôn được gọi là ASCII, nhưng không phải US-ASCII) có 18 mã cụ thể theo vùng, nhưng tôi không biết chúng là mã nào. Một điều tôi có thể nói chắc chắn - trong "ASCII" của Anh, #đã được thay thế bằng £. Ở các khu vực khác, có lẽ "ASCII" không có niềng răng, v.v.
Steve314

7
Bộ ký tự ATASCII tương tự được đặt cho các máy tính Atari 8 bit cũng thiếu {} cũng như ~ và `.
dan04

42
Xem những hai bài viết Wikipedia. Tôi chỉ đủ tuổi để vẫn còn nhớ kỷ nguyên của các bộ ký tự quốc gia 7 bit (mặc dù tôi chắc chắn rằng chúng vẫn còn tồn tại ở một số góc tối không được che chở), và cuốn sách đầu tiên tôi học được từ C thấy cần phải cảnh báo về khả năng if (x || y) { a[i] = '\0'; }trông giống như if (x öö y) ä aÄiÅ = 'Ö0'; åtrong bảng mã sai.
Ilmari Karonen

9
Một lưu ý lịch sử thú vị khác là Unix (vốn là nền tảng C cưỡi trên) có thể là hệ thống đầu tiên có ý nghĩa quan trọng (và có thể là tổng thể đầu tiên) đối với các giá trị chữ cái mặc định thành chữ thường thay vì chữ hoa. Mặc dù tôi đã không nhìn thấy tận mắt nhiều hệ thống đương đại, tôi nghĩ rằng đây là một dấu hiệu thực sự của sự tinh tế. Bên cạnh việc thực sự là hệ điều hành tốt duy nhất, Unix cũng chuyển đổi chữ hoa của bạn thành chữ thường, thay vì ngược lại. Những người đó thật tuyệt.
DigitalRoss

16
Câu chuyện vui tôi phải kể cho bạn ... trình biên dịch XL Fortran của máy trạm IBM RS / 6000 được phát triển từ trình biên dịch XL C. Trong một vài bản phát hành đầu tiên, họ đã vô tình để lại quá trình xử lý, vì vậy có một số chuỗi ký tự Fortran hợp pháp (trong một chuỗi chữ, IIRC) đã bị hiểu sai là chữ ba, dẫn đến một số lỗi thú vị!
Phil Perry

166

Đó là một C trigraph . ??!|, ??!??!nhà điều hành cũng vậy||


5
Trecraft đến từ thời kỳ mà một số bàn phím không có tất cả các phím họ có bây giờ. Nó cũng hels khi một số trình soạn thảo văn bản dành riêng các ký tự đặc biệt cho những điều đặc biệt. Nó chủ yếu là một di tích của quá khứ và một người tạo ra câu đố;)
Joel Falcou

5
Bởi vì một số bàn phím dường như không có "|" Vì vậy, một số người không có lựa chọn nào khác ngoài việc gõ đầu bàn phím nhiều lần cho đến khi xuất hiện một biểu tượng cung cấp cho họ các biểu tượng họ cần.

Và sau đó là <iso646.h>tập tin tiêu đề.
David R Tribble

149

Như đã nêu ??!??!thực chất là hai trigraphs ( ??!??!một lần nữa) mushed cùng mà được thay thế phiên dịch sang ||, tức là logic OR , bằng vi xử lý.

Bảng sau đây chứa mỗi bộ ba sẽ giúp phân biệt các kết hợp bộ ba thay thế:

Trigraph   Replaces

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

Nguồn: C: Sách hướng dẫn tham khảo Phiên bản thứ 5

Vì vậy, một bộ ba trông giống như ??(??)cuối cùng sẽ ánh xạ tới [], ??(??)??(??)sẽ được thay thế [][]và như vậy, bạn có ý tưởng.

Vì các bộ ba được thay thế trong quá trình tiền xử lý, bạn có thể sử dụng cppđể có được chế độ xem đầu ra, sử dụng trigr.cchương trình ngớ ngẩn :

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

và xử lý nó với:

cpp -trigraphs trigr.c 

Bạn sẽ nhận được một đầu ra giao diện điều khiển của

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

Như bạn có thể nhận thấy, tùy chọn -trigraphsphải được chỉ định nếu không cppsẽ đưa ra cảnh báo; điều này chỉ ra làm thế nào các bức tượng là một điều của quá khứ và không có giá trị hiện đại nào ngoài những người khó hiểu có thể va vào chúng .


Đối với lý do đằng sau việc giới thiệu các bộ ba, được hiểu rõ hơn khi xem phần lịch sử của ISO / IEC 646 :

ISO / IEC 646 và tiền thân ASCII (ANSI X3.4) phần lớn tán thành thực tiễn hiện có liên quan đến mã hóa ký tự trong ngành viễn thông.

Vì ASCII không cung cấp một số ký tự cần thiết cho các ngôn ngữ khác ngoài tiếng Anh, một số biến thể quốc gia đã được tạo ra để thay thế một số ký tự ít được sử dụng bằng các ký tự cần thiết .

(nhấn mạnh của tôi)

Vì vậy, về bản chất, một số ký tự cần thiết (những ký tự tồn tại) đã được thay thế trong một số biến thể quốc gia nhất định. Điều này dẫn đến việc đại diện thay thế bằng cách sử dụng các biểu tượng bao gồm các ký tự mà các biến thể khác vẫn có xung quanh.

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.