web-dev-qa-db-fra.com

Qu'est-ce que le C ??! ??! opérateur faire?

J'ai vu une ligne de C qui ressemblait à ceci:

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

Il a compilé correctement et semble fonctionner correctement. On dirait qu'il vérifie si une erreur s'est produite et, le cas échéant, il la gère. Mais je ne suis pas vraiment sûr de ce que cela fait réellement ou comment cela se passe. Il semble que le programmeur essaie d'exprimer ses sentiments à propos des erreurs.

Je n'ai jamais vu le ??!??! auparavant dans aucun langage de programmation et je ne trouve aucune documentation à ce sujet. (Google n'aide pas avec les termes de recherche comme ??!??!). Que fait-il et comment fonctionne l'exemple de code?

1865
Peter Olson

??! est un trigraphe qui se traduit par |. Donc, il dit:

!ErrorHasOccured() || HandleError();

qui, par court-circuit, équivaut à:

if (ErrorHasOccured())
    HandleError();

Gourou de la semaine (traite de C++ mais pertinent ici), où j'ai repris ceci.

Origine possible des trigrammes ou, comme @DwB l’a souligné dans les commentaires, c’est plus probablement dû au fait que EBCDIC est difficile (encore). Ceci la discussion sur le tableau IBM developerworks semble corroborer cette théorie.

De l'ISO/IEC 9899: 1999 §5.2.1.1, note de bas de page 12 (h/t @ Random832):

Les séquences de trigrammes permettent la saisie de caractères qui ne sont pas définis dans le jeu de codes invariant, comme décrit dans ISO/CEI 646, qui est un sous-ensemble du jeu de codes US ASCII à sept bits.

1508
user786653

Eh bien, pourquoi cela existe en général est probablement différent de celui qui existe dans votre exemple.

Tout a commencé il y a un demi-siècle avec la réaffectation des terminaux de communication sur papier en tant qu'interfaces utilisateur. À l'époque initiale d'Unix et de C, il s'agissait du télétype ASR-33.

Ce périphérique était lent (10 unités par seconde) et bruyant et laid. Sa vue sur le jeu de caractères ASCII s'est terminée à 0x5f. Il n'avait donc aucune des clés (à regarder de près):

{ | } ~ 

Les trigraphes ont été définis pour résoudre un problème spécifique. L'idée était que les programmes C puissent utiliser le sous-ensemble ASCII trouvé sur l'ASR-33 et dans d'autres environnements sans les valeurs élevées ASCII.

Votre exemple est en fait deux de ??!, chacun signifiant |, le résultat est donc ||.

Cependant, les personnes qui écrivaient du code C presque par définition avaient un équipement moderne,1 Donc, je suppose que: quelqu'un qui s'amuse ou qui s'amuse, laisse une sorte d'oeuf de Pâques dans le code pour que vous le trouviez.

Cela a bien fonctionné, cela a conduit à une question extrêmement populaire SO.

ASR-33 Teletype

Télétype ASR-33


1. D'ailleurs, les trigrammes ont été inventés par le comité ANSI, qui s'est réuni pour la première fois après que C soit devenu un succès retentissant. Aucun code C ou codeur original ne l'aurait utilisé. .
426
DigitalRoss

C'est un C trigraphe . ??! est |, donc ??!??! est l'opérateur ||

156
Joel Falcou

Comme déjà indiqué, ??!??! est essentiellement deux trigraphes (??! et ??! encore ) regroupés ensemble qui sont remplacés-traduits en ||, c'est-à-dire le OU logique , par le préprocesseur.

Le tableau suivant contenant chaque trigraphe devrait aider à lever la ambiguïté des autres combinaisons de trigrammes:

Trigraph   Replaces

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

Source: C: Manuel de référence, 5ème édition

Ainsi, un trigraphe ressemblant à ??(??) mappera finalement sur [], ??(??)??(??) sera remplacé par [][] et ainsi de suite, vous aurez l'idée.

Comme les trigrammes sont substitués lors du prétraitement, vous pouvez utiliser cpp pour obtenir vous-même une vue de la sortie, à l'aide d'un programme idiot trigr.c:

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

et le traiter avec:

cpp -trigraphs trigr.c 

Vous obtiendrez une sortie console de

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

Comme vous pouvez le constater, l'option -trigraphs doit être spécifiée, sinon cpp émettra un avertissement; cela indique comment les trigraphes appartiennent au passé et n'ont aucune valeur moderne, si ce n'est de semer la confusion parmi les personnes qui pourraient les heurter .


Quant à la raison d'être de l'introduction des trigraphes, elle est mieux comprise lorsque vous regardez la section historique de l'ISO/CEI 646 :

ISO/CEI 646 et son prédécesseur ASCII (ANSI X3.4) ont largement approuvé les pratiques existantes en matière de codage de caractères dans l'industrie des télécommunications.

Comme ASCII ne fournissait pas un nombre de caractères nécessaire pour les langues autres que l'anglais, , un certain nombre de variantes nationales ont été proposées pour remplacer caractères utilisés avec ceux nécessaires .

(c'est moi qui souligne)

Ainsi, certains caractères nécessaires (ceux pour lesquels un trigraphe existe) ont été remplacés dans certaines variantes nationales. Cela conduit à la représentation alternative utilisant des trigrammes composés de caractères que d'autres variantes avaient encore autour.

133