9
votes

Qu'est-ce que '\' réellement en C?

Aussi loin que je connais \ code> en C juste ajoute la ligne suivante comme s'il n'y avait pas une pause de ligne.

Considérez le code suivant: P>

main(){return 0;
}


11 commentaires

Qu'entendez-vous par «le code pré-traité»?


@DavidBrown: Vraisemblablement la sortie de GCC -E (ou équivalent).


ok, question différente


@Zane: Je ne l'utiliserais pas pour de longues chaînes, car c joignait déjà des littéraux à chaîne adjacents (par exemple, par exemple "foo" / * bar * / "baz" est équivalent à "foobaz" ). La seule chose que je pense que la nouvelle ligne après-nouvelle-ligne est vraiment utile pour les définitions de macro (où il vous permet de définir la définition sur plusieurs lignes).


C'est une question sur un préprocesseur de Standalone C spécifique, et non une question sur le langage C. Développement: Les compilateurs C produisent des programmes exécutables, ils ne produisent pas de code C ... Vous ne pouvez donc pas obtenir le code que vous attendiez d'un compilateur C.


Par curiosité: pourquoi êtes-vous intéressé par la manière dont le prétraiteur fonctionne du tout? Quel est le contexte? Ou êtes-vous juste curieux par vous-même?


@Tobimcnamobi Je m'attendais à ce que le code prétraité soit 2 lignes, mais quand j'ai vérifié, il reste 3 lignes. J'étais juste curieux


@ruakh backslash à la fin d'une ligne d'une ligne d'une concaténation littérale de chaîne prédée et était la voie à suivre de longues chaînes à l'époque. Maintenant, ce n'est que GOO pour les macros, comme vous le mentionnez et l'obfuscation.


Banarun, ce n'était pas la question. Veuillez répondre à la question afin que nous puissions vous aider.


@Banarun: Je ne peux pas recréer ce comportement avec GCC 4.2 sur OSX. Quelle version utilisez-vous?


@Olicharlesworth GCC 4.7.3


3 Réponses :


4
votes

Peu importe: / Le tokéniseur ne verra aucune différence. 1

mise à jour en réponse aux commentaires:

Il semble y avoir une certaine quantité de confusion quant à la production attendue du préprocesseur. Mon point est que l'attente / semble / raisonnable en un coup d'œil mais ne doit pas être spécifiée de cette manière pour que la sortie soit valide. La quantité de blanchie présente dans la sortie n'est tout simplement pas pertinente pour l'analyseur. Ce qui compte, c'est que le préprocesseur devrait traiter la ligne continue comme une ligne tout en l'interprétant.

En d'autres termes: Le préprocesseur n'est pas un outil de transformation de texte, c'est un outil de manipulation de jeton.

Si cela vous importe, vous êtes probablement

  • Utilisation du préprocesseur pour quelque chose d'autre que C / C ++
  • Traitement du code C ++ comme texte, qui est une odeur de code. (libllang et diverses bibliothèques d'analyses moins complètes vous viennent à l'esprit).

    1 (le préprocesseur est libre d'obtenir le résultat spécifié de la manière dont il voit la solution. Le résultat que vous voyez est peut-être la manière la plus efficace que les implémentations ont trouvé pour mettre en œuvre cette transformation particulière) < / p>


24 commentaires

Ou vous définissez des macros, auquel cas c'est assez important;)


OLI: En désaccord. Le comportement spécifié des macros est indépendant de WhitSpace présent dans le code prétraité


Vous pouvez couvrir la définition d'une seule macro sur plusieurs lignes, mais uniquement si vous terminez chaque ligne avec \.


Oli je sais. Mon point est que la quantité de blanchie générée entre jetons dans la sortie est sans importance (et probablement non spécifiée)


Ceci est un peu pédant, mais gardez à l'esprit que la concaténation de la ligne se produit avant le préprocesseur qui fonctionne, donc si cette étape allait mal (et ne concaté pas correctement les lignes), le prétraiteur «voir» le mauvais chose...


@Oli ce n'est pas pédant, c'est non pertinent / spéculatif. Clairement, il n'y a pas de tel bug dans la mise en œuvre :)


@Olicharlesworth veuillez fournir une preuve. Et postez que comme réponse


@ Not-SEHE: L'OP a fourni la preuve; Il / elle ne reçoit pas la sortie que l'on "s'attendait à" après avoir exécuté GCC -E (apparemment). (Et fwiw, je n'obiste pas ce comportement quand je l'essaie ...)


@Olicharlesworth qui prouve rien . Il est attendant la mauvaise chose (sur le mauvais niveau d'abstraction). Voir ici: Coliru.stacked-crooked.com/... GNU CPP est pas brisé de manière flagrante.


D'accord, je ne peux pas recréer l'observation de l'OP. Dans ce cas, il / elle utilise une version de buggy particulière, soit l'observation est incorrecte. Cependant, l'OP est attendre la bonne chose; La norme dit avec précision ce qui devrait se produire (bien que vous soulignez dans votre réponse, la divergence n'est pas pertinente dans ce contexte).


@Olicharlesworth, je vais être paresseux ici (et je dois aller au bureau): Je serais donc le plus obligé si vous pouviez effectivement creuser la citation standard supposée spécifiant ce "précision" . Je suis convaincu que le libellé se révélera pour permettre ce que nous voyons, pour les raisons précises des raisons que je décris dans ma réponse.


@Olicharlesworth Il n'y a pas d'insecte. J'ai le même résultat que l'OP, mais cela fait la bonne chose pour les macros ... Tout ce qui est dans ce qui est autorisé par la norme C. "L'OP s'attend à ce que la bonne chose" - comme cela a été expliqué, c'est faux ... il n'y a pas de "bonne chose" à attendre; La norme C ne dit rien sur un drapeau ou d'autre moyen d'observer les résultats des phases individuelles.


Merci @jim. C'est exactement mon point tout le long. (Les personnes sont fréquemment étonnées au niveau de la liberté que les implémentations de normes obtiennent lors de la mise en œuvre des spécifications.)


@Jimbalter: hmm. La norme C (99) indique assez clairement ce qui devrait arriver dans les différentes étapes de la traduction. Si GCC -E (qui est documenté pour afficher "la sortie après prétraitement") produit quelque chose qui ne correspond pas, on pourrait alors faire valoir que c'est non conforme (indépendamment du fait que cela ne compte pas dans ce cas) .


@Oli ce qui se passe dans les étapes est interne ... encore une fois, la norme C ne fournit aucun moyen pour vous de le voir. GCC -E n'est pas un compilateur C, il fait autre chose. GCC est conforme à la norme ... il compile correctement les macros. (Et nous aurions remarqué il y a longtemps si ce n'est pas le cas.)


@Jimbalter: Je pense que nous pourrions aller dans une discussion inutile;) Je vois votre point de vue, mais je dirais toujours que GCC -E est (au mieux) est (au mieux) irritalement trompeur si elle émet une autre chose que la norme implique de générer Le modèle conceptuel (étant donné qu'il pourrait générer si facilement la chose «correcte»).


@Olicharlesworth 'qui est documenté pour montrer "la sortie après prétraitement"' - pas dans ma documentation. Quoi qu'il en soit, "la sortie après prétraitement" est des structures de données internes ... Les compilateurs modernes ne produisent pas de flux de texte entre le préprocesseur et les autres étapes.


@OLICHARLESWORTHORD "Je dirais toujours que GCC -E est (au mieux) (au mieux) irritant induire en erreur" alors quoi ?? C'est un poteau de but radical qui change de paille ... La discussion concernait la norme C et la conformité. La fin.


@Jimbalter: J'étais paraphrasant de la mémoire ... La description effective semble être "Arrêt après la phase de prétraitement".


@Jimbalter: C'est bon, je concède que la norme ne limite en aucun cas la mise en œuvre ici. Mais je maintiens que ce comportement de la GCC est trompeur (et semble avoir été changé au fil du temps; 4.2 agit différemment à 4.7.2), et que cela pourrait être considéré comme un "bogue" (les bugs ne sont pas limités uniquement à la conformité des normes) .


C'est bon, nous pouvons réparer nos propres modèles conceptuels encore plus facilement que les compilateurs Foss!


@Jimbalter: Pas besoin de ce ton. J'ai admis que j'avais tort, et j'ai fait un point différent. Ce n'est pas "abus" ...


@Jimbalter: soupir ... En répétant le point, j'espérais que je pourrais provoquer une réponse intéressante "je suis d'accord" ou "je suis en désaccord". Cela n'était certainement pas hors de propos de la question initiale.


@Jimbalter: Je suis vivement intéressé à savoir si les gens sont d'accord ou non, car je suis intéressé à savoir quand mon modèle du monde est faux. Mais je suis d'accord, nous sont abuser du système de commentaire, alors laissez-le ici?



10
votes

de Section K & R A.12 Prétraitement :

A.12.2 Épissage de la ligne

lignes qui se terminent par le caractère de barre oblique inverse \ sont Plié en supprimant la barre oblique inverse et le caractère Newline suivant. Cela se produit avant la division en jetons.


4 commentaires

Ceci est particulièrement utile lorsque les gens veulent que Macro s'étend sur plusieurs lignes


@Marounmaroun, huile a ajouté une référence en ligne pour pdf


@Olicharlesworth la question "Que fait" "faire en C?" C'est parfaitement répondu par cela, je pense.


@Tobimcnamobi: Bien sûr. Mais la vraie question semble être "pourquoi je vois-je ce comportement particulier?".



10
votes

Oui, votre résultat attendu est celui requis par les normes C et C ++. La barre oblique inverse échappe simplement à la nouvelle ligne, c'est-à-dire la séquence de Backslash-Newline est supprimée.

GCC 4.2.1 de mon installation d'OS X donne le résultat attendu, de même que Clang. En outre, l'ajout d'un #define au début et à tester avec xxx

donne le résultat correct xxx

Peut-être GCC -E fait un traitement supplémentaire après le prétraitement et avant de la sortir. En tout état de cause, la rupture de ligne vue par le reste du préprocesseur semble être au bon endroit. Donc, c'est un bug cosmétique.

update: selon le FAQ GCC , -E (ou le paramètre par défaut de la commande CPP ) tente de mettre des jetons de sortie de manière approximativement le même emplacement visuel que les jetons d'entrée. Pour obtenir une sortie "brute", spécifiez -p aussi. Cela corrige les problèmes observés.

probablement ce qui s'est passé:

  1. En préservant l'apparence visuelle, les jetons non séparés par des espaces sont conservés ensemble.
  2. L'épissure de ligne se produit avant que les espaces ne soient identifiés pour ce qui précède.
  3. Le { et retour Les jetons sont regroupés dans le même bloc visuel.
  4. 0 suit un espace et son emplacement sur la ligne suivante est dûment noté.

    Plug: Si cela est vraiment important pour vous, j'ai mis en place Mon préprocesseur avec une mise en œuvre correcte des modes "jolis" préprocessés bruts et espacés. À la suite de cette discussion, je ajouté épissures ligne aux espaces préservés . Ce n'est pas vraiment conçu comme un outil autonome, cependant. C'est un banc d'essai pour un cadre de compilateur qui se trouve être une bibliothèque de préprocesseur C ++ 11 entièrement compilée, qui dispose d'un pilote de ligne de commande miniature. (Les messages d'erreur sont à égalité avec GCC ou Clang, Sans Color, cependant.)


6 commentaires

"Votre résultat attendu est celui requis par les normes C et C ++." - Pas du tout - les normes ne nécessitent pas que les implémentations de la sortie C de la production C et ne disent rien sur le format du code C généré par des programmes qui font. "Donc c'est un bug cosmétique." - Ce n'est pas du tout un bogue, car le format de la sortie de GCC -E n'est pas spécifié, à part cela, il sera compilé correctement.


@Jimbalter La sortie de la phase 4 est suffisamment définie pour être observable. Il se compose d'espaces, de nouvelles lignes et de jetons de prétraitement. Les normes ne nécessitent pas que cela soit observable, mais si la production de préprocesseur est en effet ce qu'il observe, la norme spécifie ce qu'elle devrait être et où se passe la nouvelle ligne. (Il n'y a pas d'indication textuelle des frontières de jeton, la représentation du texte tombe donc un peu courte.) Je suis sûr que cela est documenté et, étant donné que GCC est censé être conforme à sa propre documentation, elle pourrait être plus grave comme un bug. gcc.gnu.org/bugzilla/show_bug.cgi?id=57714


J'ai reconsidéré cela et j'accepte que c'est un bogue GCC, car l'exécution de la sortie de GCC -E via le compilateur donnera la mauvaise numéro de ligne pour une erreur si, disons, le 0 dans le code de l'OP est remplacé par x ou quelque chose d'autre non autorisé à ce point. Il y a une réponse d'Andrew Pinski à votre rapport de Bugzilla affirmant que c'est la bonne sortie, mais il est clairement faux.


Il est possible que les personnes du GCC aient mal interprété "chaque instance d'un caractère de barre oblique inverse () immédiatement suivie d'un caractère nouveau de ligne est supprimée" pour signifier que la barre oblique inverse est supprimée mais la nouvelle ligne n'est pas. La langue est ambiguë, mais l'intention est certainement que "l'instance" désigne les deux personnages.


@Jimbalter Cela ressemble à un simple accident, ou une mauvaise couverture de test. Andrew était mon pote à Apple Back ~ il y a 10 ans, mais il ne semble pas se souvenir de moi ... et il a de meilleures choses à faire: p. À en juger par l'horloge, il pourrait être rentré chez lui maintenant.


Oups, mon commentaire sur les numéros de ligne est faux. S'il y a une erreur dans retour et 0 , les messages d'erreur indiqueront des numéros de ligne différents plutôt que le même. Il est impossible de l'obtenir complètement bien parce que les directives #line ne peuvent pas se produire à mi-parcours. Bien entendu, les directives de ligne ne font pas partie d'aucune phase de la traduction de c. Nous sommes donc de retour à mon point d'origine que la norme ne spécifie pas la sortie de GCC -E et il n'y a donc pas d'insecte. On peut affirmer que la documentation devrait préciser que la sortie ne respecte pas quoi que ce soit spécifié par la norme.