Lo que hace el ??!??! operador hacer en C?

Vi una línea de C que se veía así:

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

Se compiló correctamente y parece funcionar correctamente. Parece que está comprobando si se ha producido un error y, si es así, lo gestiona. Pero no estoy realmente seguro de qué está haciendo realmente o cómo lo está haciendo. Parece que el programador está tratando de expresar sus sentimientos acerca de los errores.

Nunca he visto el ??!??! antes en cualquier lenguaje de programación, y no puedo encontrar documentación para ello en ninguna parte. (Google no ayuda con términos de búsqueda como ??!??!). ¿Qué hace y cómo funciona el código de muestra?

preguntado Oct 19 '11, 13:10

@KadekM, mover la negación al nombre de la función no genera un código limpio, sino todo lo contrario. -

Lamentablemente esta joya de programa no funcionará en C ++ 17 y más reciente. -

curioso, ¿dónde está este código? abierto para que el público lo vea? -

4 Respuestas

??! es un trígrafo que se traduce en |. Entonces dice:

!ErrorHasOccured() || HandleError();

que, por cortocircuito, equivale a:

if (ErrorHasOccured())
    HandleError();

Gurú de la semana (trata con C ++ pero relevante aquí), donde recogí esto.

Posible origen de los trígrafos o como señala @DwB en los comentarios, es más probable que se deba a que EBCDIC es difícil (de nuevo). Esta La discusión en la junta de IBM developerworks parece apoyar esa teoría.

De ISO / IEC 9899: 1999 §5.2.1.1, nota al pie 12 (h / t @Random832):

Las secuencias de trígrafos permiten la entrada de caracteres que no están definidos en el conjunto de códigos invariantes como se describe en ISO / IEC 646, que es un subconjunto del conjunto de códigos ASCII de siete bits de EE. UU.

Respondido 19 ago 21, 06:08

Los trígrafos originalmente eran necesarios en caso de que su teclado no tuviera, por ejemplo, un '|' símbolo. Aquí es el programador deliberadamente molesto o alguna 'característica' extraña del editor - Martín Beckett

No es necesariamente EBCDIC: el conjunto de caracteres que requieren trígrafos coincide casi exactamente con el conjunto de caracteres que no son invariantes en ISO-646 (es decir, los antiguos estándares 'ascii nacionales'). - Random832

Una alternativa perfectamente legible sería ErrorHasOccurred() && HandleError(); Es decir, si está acostumbrado a shell scripting. :) - ñame marcovic

Solo tenga en cuenta que muchos estándares de codificación prohíben específicamente el uso de Trigraphs y Digraphs, y muchos compiladores y analizadores estáticos marcarán su uso. - Luciano

No válido desde C ++ 17: | - Val sigue con Monica

Bueno, la razón por la que esto existe en general probablemente sea diferente a la razón por la que existe en su ejemplo.

Todo comenzó hace medio siglo con la reutilización de terminales de comunicación impresos como interfaces de usuario de computadora. En la era inicial de Unix y C, ese era el teletipo ASR-33.

Este dispositivo era lento (10 cps) y ruidoso y feo y su vista del conjunto de caracteres ASCII terminaba en 0x5f, por lo que no tenía (mire de cerca la imagen) ninguna de las claves:

{ | } ~ 

Los trígrafos se definieron para solucionar un problema específico. La idea era que los programas C pudieran usar el subconjunto ASCII que se encuentra en el ASR-33 y en otros entornos que no tienen los valores ASCII altos.

Tu ejemplo es en realidad dos de ??!, cada significado |, entonces el resultado es ||.

Sin embargo, las personas que escriben código C casi por definición tenían equipos modernos,1 entonces mi conjetura es: alguien presumiendo o divirtiéndose, dejando una especie de huevo de Pascua en el código para que lo encuentres.

Seguro que funcionó, llevó a una pregunta SO muy popular.

Teletipo ASR-33

                                            Teletipo ASR-33


1. Por lo demás, los trígrafos fueron inventados por el comité ANSI, que se reunió por primera vez después de C se convirtió en un gran éxito, por lo que ninguno de los codificadores o codificadores originales de C los habría usado.

Respondido 15 ago 16, 19:08

No es el único caso de caracteres faltantes, en el teclado y en el conjunto de caracteres. Es probable que el Commodore 64 sea más familiar para muchas personas de treinta y tantos años o más; los conjuntos de caracteres mostrados carecían de llaves (y probablemente la barra y la tilde también), en este caso porque el "ASCII" no era ASCII. . En ECMA-6 (casi siempre llamado ASCII, pero no US-ASCII) había 18 códigos específicos de la región, pero no sé qué códigos eran. Lo único que puedo decir con certeza: en el "ASCII" británico, # fue reemplazado por £. En otras regiones, tal vez "ASCII" no tenía aparatos ortopédicos, etc. Steve314

El conjunto de caracteres ATASCII similar para computadoras Atari de 8 bits también carecía de {} así como ~ y `. - dan04

Ver estos dos Artículos de Wikipedia. Tengo la edad suficiente para recordar la era de los juegos de caracteres nacionales de 7 bits (aunque estoy seguro de que todavía persisten en algunos rincones oscuros sin barrer), y el libro del que aprendí C por primera vez consideró necesario advertir sobre el Posibilidad de if (x || y) { a[i] = '\0'; } luciendo como if (x öö y) ä aÄiÅ = 'Ö0'; å en el juego de caracteres incorrecto. - ilmari karonen

Otra nota histórica interesante es que Unix (que fue la gran plataforma en la que se montó C) puede haber sido el primer sistema de alguna importancia (y tal vez el primero en general) en valores alfabéticos predeterminados en minúsculas en lugar de mayúsculas. Aunque no he visto con mis propios ojos muchos sistemas contemporáneos, creo que esto fue un verdadero signo de sofisticación. Además de ser realmente el único sistema operativo decente, Unix también convirtió las mayúsculas a minúsculas, en lugar de viceversa. Esos tipos eran realmente geniales. - DigitalRoss

Tengo que contarte una historia divertida ... El compilador XL Fortran de la estación de trabajo IBM RS / 6000 se desarrolló a partir del compilador XL C. En los primeros lanzamientos, se dejaron accidentalmente en el procesamiento de trígrafos, por lo que hubo algunas secuencias legítimas de caracteres de Fortran (en una cadena literal, IIRC) que se malinterpretaron como trígrafos de C, lo que provocó algunos errores interesantes. - phil perry

Es una c trígrafo. ??! is |, asi que ??!??! es el operador ||

respondido 08 mar '17, 22:03

trigraph provienen de un período en el que algunos teclados no tenían todas las teclas que tienen ahora. También ayuda cuando algún editor de texto reserva caracteres especiales para cosas especiales. Es principalmente una reliquia del pasado y un habilitador de cuestionarios;) - joel falcou

Porque algunos teclados aparentemente no tienen "|" por lo que algunas personas no tienen otra opción que golpear el teclado repetidamente hasta que aparezca un trígrafo que les proporcione los símbolos que necesitan. - Búho

Y luego está el <iso646.h> archivo de cabecera. - David Tribble

Como ya se dijo ??!??! es esencialmente dos trigrafos (??! y ??! de nuevo) mezclados juntos que son reemplazados-traducidos a ||, es decir, el OR lógico, por el preprocesador.

La siguiente tabla que contiene todos los trígrafos debería ayudar a eliminar la ambigüedad de las combinaciones de trígrafos alternativos:

Trigraph   Replaces

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

Fuente: C: Manual de referencia 5ta edición

Entonces, un trígrafo que parece ??(??) eventualmente se mapeará a [], ??(??)??(??) será reemplazado por [][] y así sucesivamente, te haces una idea.

Dado que los trígrafos se sustituyen durante el preprocesamiento, puede utilizar cpp para obtener una vista de la salida usted mismo, utilizando una tontería trigr.c programa:

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

y procesándolo con:

cpp -trigraphs trigr.c 

Obtendrá una salida de consola de

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

Como puede notar, la opción -trigraphs debe especificarse o de lo contrario cpp emitirá una advertencia; esto indica como Los trígrafos son cosa del pasado y no tienen ningún valor moderno más que confundir a las personas que podrían toparse con ellos..


En cuanto a la razón fundamental detrás de la introducción de los trígrafos, se comprende mejor cuando se mira la sección de historia de ISO / IEC 646:

ISO / IEC 646 y su predecesor ASCII (ANSI X3.4) respaldaron en gran medida la práctica existente con respecto a las codificaciones de caracteres en la industria de las telecomunicaciones.

Como ASCII no proporcionó una cantidad de caracteres necesarios para idiomas distintos del inglés, Se hicieron una serie de variantes nacionales que sustituyeron algunos caracteres menos utilizados por otros necesarios..

(énfasis mío)

Entonces, en esencia, algunos caracteres necesarios (aquellos para los que existe un trígrafo) fueron reemplazados en ciertas variantes nacionales. Esto lleva a la representación alternativa utilizando trígrafos compuestos por personajes que todavía tenían otras variantes.

Respondido el 20 de junio de 20 a las 10:06

Buena explicación ... esto también muestra por qué los marcadores de posición como char *date = "??-??-??!" puede que no produzca lo que espera (esto en realidad produce char *date = "~~|";) - Andrés

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.