Pregunta

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

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

Se compiló correctamente y parece funcionar bien. Parece que está comprobando si se ha producido un error, y si lo ha hecho, lo maneja. 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 sobre los errores.

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

¿Fue útil?

Solución

??! es un trigraph que se traduce en |. Entonces dice:

!ErrorHasOccured() || HandleError();

que, debido a cortocircuito, es equivalente 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 @DWB señala en los comentarios, es más probable debido a que EBCDIC es difícil (nuevamente). Este 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 trigraph permiten la entrada de caracteres que no se definen en el código invariante establecido como se describe en ISO/IEC 646, que es un subconjunto del conjunto de código ASCII de siete bits de EE. UU.

Otros consejos

Bueno, por qué esto existe en general es probablemente diferente de por qué existe en su ejemplo.

Todo comenzó hace medio siglo con la reutilización de terminales de comunicación de copia impresa como interfaces de usuarios de computadora. En la era inicial de UNIX y C, esa era el teletipo ASR-33.

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

{ | } ~ 

Los trigraphs 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 faltan los altos valores ASCII.

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

Sin embargo, las personas que escriben el código C casi por definición tenían equipos modernos,1 Entonces mi suposición es: alguien que se presenta o se divierte a sí mismo, Dejando una especie de huevo de Pascua en el código para que lo encuentre.

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

ASR-33 Teletype

Teletipo ASR-33


1. Para el caso, los trigraphs fueron inventados por el comité ANSI, que se reunió por primera vez después C se convierte en un éxito desbocado, por lo que ninguno de los códigos C originales o codificadores los habría usado.

Es una C trigraph. ??! es |, asi que ??!??! es el operador ||

Como ya se dijo ??!??! es esencialmente dos trigraphs (??! y ??! nuevamente) se reemplazó que se reemplazan a ||, es decir, el lógico o, por el preprocesador.

La siguiente tabla que contiene cada trigraph debe ayudar a desambiguar las combinaciones de trigraph alternativas:

Trigraph   Replaces

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

Fuente: C: un manual de referencia 5th Edition

Entonces un trigraf que se parece ??(??) eventualmente mapeará a [], ??(??)??(??) será reemplazado por [][] Y así sucesivamente, tienes la idea.

Dado que los trigraphs se sustituyen durante el preprocesamiento, puede usar cpp Para obtener una vista de la salida usted mismo, usando una tontería trigr.c programa:

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

y procesarlo 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 cómo Los trigraphs son cosa del pasado y de ningún valor moderno que no sea confundir a las personas que podrían toparse con ellos.


En cuanto a la justificación detrás de la introducción de los trigraphs, se entiende mejor al mirar 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 personajes en la industria de las telecomunicaciones.

Como ASCII no proporcionó varios caracteres necesarios para idiomas distintos del inglés, Se hicieron varias variantes nacionales que sustituyeron a algunos personajes menos utilizados con los necesarios.

(énfasis mío)

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top