La mise en œuvre par GCC des équerres comprend. Pourquoi faut-il que ce soit comme décrit ci-dessous?

11

Ce document dans sa section 2.6 Calculé comprend le paragraphe suivant:

Si la ligne se développe en un jeton commençant par un jeton <et incluant un jeton>, les jetons entre le <et le premier> sont combinés pour former le nom de fichier à inclure. Tout espace entre les jetons est réduit à un seul espace; alors tout espace après le <initial est conservé, mais un espace de fin avant la fermeture> est ignoré . CPP recherche le fichier selon les règles d'inclinaison.

Je sais que cette implémentation est définie, mais pourquoi doit-il en être ainsi pour GCC? Je me réfère spécifiquement à la phrase surlignée ci-dessus.

ÉDITER

Je viens de remarquer que le troisième paragraphe avant celui cité ci-dessus dit ceci:

Vous devez être prudent lorsque vous définissez la macro. #defineenregistre les jetons, pas le texte. Le préprocesseur n'a aucun moyen de savoir que la macro sera utilisée comme argument de #include, donc il génère des jetons ordinaires, pas un nom d'en-tête. Il est peu probable que cela cause des problèmes si vous utilisez des inclusions entre guillemets, qui sont suffisamment proches des constantes de chaîne. Cependant, si vous utilisez des équerres, vous risquez d'avoir des problèmes .

Quelqu'un sait-il quel genre de problème est signalé ici?

Ayrosa
la source
6
La meilleure supposition est que les développeurs de GCC pensent qu'avoir des espaces à la fin d'un nom de fichier est une abomination.
user3386109
1
Les noms de fichiers avec des espaces de début et / ou de fin sont très difficiles à utiliser, en particulier sous Windows.
Remy Lebeau
1
Ce n'est pas parce qu'il a été défini comme ça que cela doit nécessairement être défini comme ça. Il n'est pas mandaté par la norme.
eerorika
Visual Studio supprime l'espace initial et final, donc se comporte différemment. HP aCC se comporte comme gcc (peut-être pour des raisons de compatibilité).
Slimak
Parfois, la documentation décrit simplement ce que le code fait au lieu de l'inverse, en particulier dans les cas qui n'ont pas d'importance (vous pouvez utiliser n'importe quel espace n'importe où si vous utilisez des guillemets doubles).
rustyx

Réponses:

9

Je suppose que l'implémenteur a choisi la manière la plus simple lorsqu'ils ont implémenté cette fonctionnalité, sans y penser beaucoup.

Il semble que la mise en œuvre initiale ait atterri en 2000-07-03 (il y a deux décennies!). La partie pertinente ressemble à ( source ):

  for (;;)
    {
      t = cpp_get_token (pfile);
      if (t->type == CPP_GREATER || t->type == CPP_EOF)
        break;

      CPP_RESERVE (pfile, TOKEN_LEN (t));
      if (t->flags & PREV_WHITE)
        CPP_PUTC_Q (pfile, ' ');
      pfile->limit = spell_token (pfile, t, pfile->limit);
    }

Notamment, il éclate lorsqu'il voit le CPP_GREATERjeton (c'est-à-dire >), avant de réserver de la mémoire pour le jeton. Cela a du sens, car il n'est pas nécessaire d'allouer de la mémoire lorsque le jeton ne sera pas écrit dans le tampon.

Ensuite, seulement après que la mémoire est réservée, le préprocesseur vérifie si le jeton a le blanc précédent ( t->flags & PREV_WHITE) et quand il le fait, écrit un caractère blanc dans le tampon.

Par conséquent, dans < foo / bar >, seuls les espaces avant foo(c'est-à-dire après l'initiale <) /et barsont conservés.

cpplearner
la source
Brillant, excellente réponse. C'est la première fois que j'ai l'occasion de voir un morceau de code dans GCC. Merci pour ça.
Ayrosa
Mais n'est-il pas vrai que la condition if (t->flags & PREV_WHITE) CPP_PUTC_Q (pfile, ' ');contredit ce qui est dit dans le document: "Tout espace entre les jetons est réduit à un seul espace; ..."?
Ayrosa