Como já foi dito, ??!??!são essencialmente dois trigramas ( ??!e ??!novamente) misturados que são substituídos - traduzidos para ||, ou seja, o OR lógico , pelo pré-processador.
A tabela a seguir, contendo todos os trigramas, deve ajudar a desambiguar combinações alternativas de trigramas:
Trigraph Replaces
??( [
??) ]
??< {
??> }
??/ \
??' ^
??= #
??! |
??- ~
Fonte: C: Um Manual de Referência 5ª Edição
Assim, um trigrama que pareça ??(??)eventualmente será mapeado para [], ??(??)??(??)será substituído [][]e assim por diante, você entenderá.
Como os trigrafs são substituídos durante o pré-processamento, você pode usar cpppara obter uma visão da saída, usando um trigr.cprograma bobo :
void main(){ const char *s = "??!??!"; }
e processando-o com:
cpp -trigraphs trigr.c
Você obterá uma saída do console de
void main(){ const char *s = "||"; }
Como você pode perceber, a opção -trigraphsdeve ser especificada ou então cppemitirá um aviso; isso indica como os trigramas são coisa do passado e não têm valor moderno além de confundir pessoas que possam esbarrar neles .
Quanto à justificativa por trás da introdução dos trigramas, é melhor compreendida ao examinar a seção de histórico da ISO / IEC 646 :
A ISO / IEC 646 e seu antecessor ASCII (ANSI X3.4) endossaram amplamente as práticas existentes em relação a codificações de caracteres no setor de telecomunicações.
Como o ASCII não forneceu um número de caracteres necessários para outros idiomas além do inglês, foram feitas várias variantes nacionais que substituíram alguns caracteres menos utilizados pelos necessários .
(ênfase minha)
Portanto, em essência, alguns caracteres necessários (aqueles para os quais existe um trigrama) foram substituídos em certas variantes nacionais. Isso leva à representação alternativa usando trigramas compostos por caracteres que outras variantes ainda possuíam.
!ErrorHasOccurred() ??!???! HandleError();compilar? É isso??!???!. Prova o ponto?