web-dev-qa-db-fra.com

Quand les compilateurs C ++ ont-ils commencé à considérer plus de deux chiffres hexagonaux dans des évasions de caractère littéral string?

J'ai une chaîne littérale (générée) en C++ pouvant contenir des caractères à échapper à l'aide de la \x notation. Par exemple:

char foo[] = "\xABEcho";

Cependant, g ++ (version 4.1.2 si cela compte) jette une erreur:

test.cpp:1: error: hex escape sequence out of range

Le compilateur semble envisager de considérer les caractères Ec dans le cadre du numéro hexagonal précédent (car ils ressemblent à des chiffres hexagonaux). Étant donné qu'un numéro hexagonal à quatre chiffres ne correspond pas à un char, une erreur est soulevée. Évidemment pour un large littéral à chaîne L"\xABEcho" Le premier personnage serait U + Abec, suivi de L"ho".

Il semble que cela a changé de temps au cours des deux dernières décennies et je n'ai jamais remarqué. Je suis presque certain que les anciens compilateurs C ne considèrent que deux chiffres hex après \x, et ne pas regarder plus loin.

Je peux penser à une solution de contournement pour cela:

char foo[] = "\xAB""Echo";

mais c'est un peu moche. Donc, j'ai trois questions:

  • Quand cela a-t-il changé?

  • Pourquoi le compilateur n'accepte-t-il que> Hex à 2 chiffres s'échappe pour des littéraux stricts à deux chiffres?

  • Y a-t-il une solution de contournement moins gênant que ce qui précède?

57
Greg Hewgill

GCC est seulement suivant la norme . # 877 : "Chaque séquence d'évacuation hexadécimale [...] est la plus longue séquence de caractères pouvant constituer la séquence d'échappement."

26

J'ai trouvé des réponses à mes questions:

  • C++ a toujours été de cette façon (vérifié STROSTRUP 3RD Edition, n'en avait pas plus tôt). K & R 1ST Edition n'a pas mentionné \x du tout (le seul caractère échappe disponible à cette époque était octal). K & R 2nd Edition déclare:

    '\xhh'
    

    HH est un ou plusieurs chiffres hexadécimaux (0 ... 9, un ... F, un ... F).

    il semble donc que ce comportement existe depuis ANSI C.

  • Bien qu'il soit possible que le compilateur n'accepte que> 2 caractères pour des littéraux à large string, cela compliquerait inutilement la grammaire.

  • Il y a en effet une solution de contournement moins maladroite:

    char foo[] = "\u00ABEcho";
    

    Les \u Escape accepte quatre chiffres hexagonales toujours.

Mise à jour: l'utilisation de \u n'est pas tout à fait applicable dans toutes les situations car la plupart ASCII caractères sont (pour une raison quelconque) non autorisée à être spécifiée à l'aide de \u. Voici un extrait de GCC:

/* The standard permits $, @ and ` to be specified as UCNs.  We use
     hex escapes so that this also works with EBCDIC hosts.  */
  else if ((result < 0xa0
            && (result != 0x24 && result != 0x40 && result != 0x60))
           || (result & 0x80000000)
           || (result >= 0xD800 && result <= 0xDFFF))
    {
      cpp_error (pfile, CPP_DL_ERROR,
                 "%.*s is not a valid universal character",
                 (int) (str - base), base);
      result = 1;
    }
21
Greg Hewgill

J'ai résolu ceci en spécifiant le caractère suivant avec\xnn aussi. Malheureusement, vous devez l'utiliser aussi longtemps qu'il existe de la gamme [A..f]. ex. "\ xnEceau" est remplacé par "\ xnn\x65\x63\x65g"

4
mike b.

Je suis sûr que C++ a toujours été de cette façon. Dans tous les cas, CHAR_BIT peut être supérieur à 8, auquel cas '\xABE' ou '\xABEc' pourrait être valide.

3
Ben Voigt