OVH Cloud OVH Cloud

preprocesseur : utilisation de ## et de «::»

33 réponses
Avatar
fabien.chene
Bonsoir,

Est-il possible d'utiliser ## pour concaténer deux mots, dont le
deuxième est préfixé de «::» ?
Un exemple qui illustre ma question :

#define CAT( a, b ) a ## b

struct Foo
{
typedef int type;
};

template <class T>
CAT( typename T, ::type ) f( T )
{
CAT( typename T, ::type ) i = 2;
return i;
}

g++ rale et me dit que T:: type n'est pas un token de preprocessing
valide.

icc ne bronche pas. Est-ce légitime ? Même si ça ne l'est pas, y a
t'il une façon d'invoquer g++ pour obtenir un fonctionnement similaire
à icc ?

Merci.

--
Fab

10 réponses

1 2 3 4
Avatar
fabien.chene
Olivier Miakinen <om+ writes:

« [...] Each comment is replaced by
one space character. [...] ». C'est dans les phases de
traduction, et ça a lieu lors de la tokenisation. « a/**/b » est
l'équivalent de « a b ».


Voilà. C'est équivalent, et c'est bien ce dont il a besoin. Mais c'est
vrai que du coup l'utilisation d'une macro est parfaitement inutile.


Dans mon contexte si. C'est utile car BOOST_PP_LIST_FOR_EACH attend
bien une macro en paramètre. Mon problème n'est pas encore
complètement réglé, mais c'est en bonne voie :-)


--
Fab


Avatar
James Kanze
Jean-Marc Bourguet wrote:
Fabien LE LEZ writes:


On Thu, 29 Jun 2006 23:25:22 +0200, (Fabien
Chêne):



(Donc,
avec certains préprocesseurs, ton CAT s'écrivait a/**/b ;
Ceci fonctionne

Il me semble qu'en C++, ça ne marche pas, car un commentaire est

considéré comme un séparateur.



ca marche a coup sur dans son cas car il n'a pas besoin de faire un
token a partir de plusieurs.


Que ce soit en C++ ou en C, il me semble me souvenir avoir verifie que
si on respecte la lettre de la norme, ca ne devrait pas pouvoir
remplacer ##. Ca ne m'etonnerait pas que ca le puisse parfois en
pratique.


Ça m'étonnerait même que ça marche en pratique, sauf
spécification des options particulières pour démander
l'émulation du préprocesseur de Reisser. Les règles en C++ sont
exactement celles du C90 ; elles datent donc de plus de quinze
ans.

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34




Avatar
James Kanze
Fabien Chêne wrote:
"kanze" writes:


[...]
Je crois que cela correspond à la politique de GCC que
j'observe, diagnostiquer les comportements indéfinis comme des
erreurs à la compilation.
Tout à fait, et c'est un but très louable en soi. Le seul

problème, c'est quand en fait, le « comportement indéfini » a
en fait toujours marcher, partout, et de ce fait, se trouver
activement utiliser dans beaucoup de code. Même dans ces cas, en
avertir, c'est bien. Mais tout le monde n'a pas forcément envie
de réécrire tout leur code du jour à lendemain, même si
formellement, c'est incorrect.



Entièrement d'accord. Le compilateur pourrait nous proposer
une option pour accepter le code. Je croyais que c'est ce
qu'il était censé fournir, pour ce qui concerne
-traditional-cpp ...


Le problème alors, c'est quelle tradition. Avant la norme, il y
en avait deux : AT&T et Reisser. Quelque chose comme
« a/**/b » donnait bien deux tokens, a et b avec AT&T, mais un
seul, ab avec Reisser.

Et évidemment, « a ## b » était illégal dans les deux. En
mode traditionnelle, je dirais qu'ou bien, on le rejette
complètement, ou bien (et mieux, à mon avis), on lui donne sa
signification en ISO C.

Un autre cas qui a été évoqué ici, il y a quelques mois :


class A; std::vector<A> v; // A incomplet, comportement indéfini pour
// un composant de la bibliothèque standard


Une option dans GCC/g++ pour accepter ce code serait assez
appréciable.


Je croyais qu'il l'acceptait par défaut:-). (J'avais bien
quelque cas semblable, où j'avais oublié d'implémenter la moitié
de ce qu'exige la norme, qui marchait bien jusqu'à peu. Quand
j'ai ajouté des options qu'il faut à la compilation pour qu'il
vérifie de telles choses.)

Le mieux serait que la prochaine norme l'accepte,
est-ce en prévision ?


Pas du tout. Au contraire, s'il y a une évolution, ça serait
dans le sens d'exiger une diagnostique. (Mais je ne crois pas
que cette évolution -- les conceptes -- propage jusque dans la
bibliothèque cette fois-ci. Le temps est trop serré.)

La première idée que j'ai eu fut d'invoquer g++ -E -P
-traditional-cpp, mais curieusement, sans plus de succès.
Alors là, c'est curieux. Parce que si -traditional-cpp doit

signifier ce que le nom semble, il faudrait bien l'accepter. De
l'autre côté : -traditional-cpp, est-ce le préprocesseur de
Riesser, ou celui de AT&T ? Ni l'un ni l'autre n'exigeait que
le résultat d'une concatenation soit un token. Mais ni l'un ni
l'autre ne connaissait ## non plus : Riesser utiliser a/**/b,
et AT&T a, puis un saut de ligne, et b au début de la ligne
suivant.



La documentation de cette option est un peu spartiate, comment
savoir s'il imite un Riesser ou un AT&T ou autre ?


Envoyer un rapport d'erreur ? Si on a une option, et qu'on ne
sait pas ce qu'il fait, c'est bien un défaut, je crois. (Je
crois aussi que l'équipe de g++ le reconnaîtra comme tel. C'est
fini, les jours où la réponse à tels criticismes était : la
documentation, c'est la source. D'après mes expériences
récentes, l'équipe g++ se comporte d'une façon plus
professionnelle que beaucoup d'équipes commercielles.)

-traditional-cpp
Try to imitate the behavior of old-fashioned C preprocessors, as
opposed to ISO C preprocessors.


Peut-être il essaie à accepter les deux.

Vu le « Try », comment dire que l'option ne repecte pas le
cahier des charges ? :-)


C'est une façon de parler, je crois. Mais peut-être aussi une
reconnaissance de l'impossibilité, vue les divergences des
préprocesseurs « old-fashioned ».

J'ajouterais que, vue que c'est une hack pour supporter quelque
chose qui a changé il y a plus de quinze ans, je comprendrais
bien qu'il n'y investit plus beaucoup d'effort, voire même qu'il
supprime l'option d'ici peu. Qu'on change quelque chose qui a
marché d'une version à l'autre, sans même qu'il y a eu un
avertissement entre-temps, je ne suis pas d'accord. Mais je
reconnais des limites quand même -- au bout de quinze ans, on
pourrait prétendre que les utilisateurs ont eu le temps de faire
l'évolution.

--
James Kanze
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34



Avatar
fabien.chene
James Kanze writes:

La première idée que j'ai eu fut d'invoquer g++ -E -P
-traditional-cpp, mais curieusement, sans plus de succès.
Alors là, c'est curieux. Parce que si -traditional-cpp doit

signifier ce que le nom semble, il faudrait bien l'accepter.




(ça me parait maintenant logique qu'il ne l'accepte pas, étant donné que
-- comme tu le dis -- ## était alors inconnu)

De l'autre côté : -traditional-cpp, est-ce le préprocesseur de
Riesser, ou celui de AT&T ? Ni l'un ni l'autre n'exigeait que le
résultat d'une concatenation soit un token. Mais ni l'un ni
l'autre ne connaissait ## non plus : Riesser utiliser a/**/b, et
AT&T a, puis un saut de ligne, et b au début de la ligne
suivant.


La documentation de cette option est un peu spartiate, comment
savoir s'il imite un Riesser ou un AT&T ou autre ?


Envoyer un rapport d'erreur ? Si on a une option, et qu'on ne
sait pas ce qu'il fait, c'est bien un défaut, je crois.


Je crois aussi.
A noter que si l'on se réfère aux manuels de GCC-2.95.3, et de
GCC-3.0.4, on a déjà plus de détail :

-traditional-cpp

Attempt to support some aspects of traditional C
preprocessors. Specifically:

* Comments convert to nothing at all, rather than to a
space. This allows traditional token concatenation.

* In a preprocessing directive, the `#' symbol must appear as
the first character of a line.

* Macro arguments are recognized within string constants in a
macro definition (and their values are stringified, though
without additional quote marks, when they appear in such a
context). The preprocessor always considers a string
constant to end at a newline.

* The predefined macro __STDC__ is not defined when you use
`-traditional', but __GNUC__ is (since the GNU extensions
which __GNUC__ indicates are not affected by
`-traditional'). If you need to write header files that work
differently depending on whether `-traditional' is in use,
by testing both of these predefined macros you can
distinguish four situations: GNU C, traditional GNU C, other
ISO C compilers, and other old C compilers. The predefined
macro __STDC_VERSION__ is also not defined when you use
`-traditional'. See section `Standard Predefined Macros' in
The C Preprocessor, for more discussion of these and other
predefined macros.

* The preprocessor considers a string constant to end at a
newline (unless the newline is escaped with `'). (Without
`-traditional', string constants can contain the newline
character as typed.)

Apparemment, au niveau de la concaténation traditionelle, il tendait à
imiter le préprocesseur de Reisser. Par contre, il n'est pas dit que
le résultat d'une concaténation soit nécessairement un token valide.

Dans les versions suivantes de la documentation de GCC, on a le droit
a plus minimaliste, et au moins le point sur la concaténation a
changé, et dans les versions de GCC que j'ai, il n'imite plus le
preprocesseur de Reisser, le commentaire est équivalent à un
espace.

J'ajouterais que, vue que c'est une hack pour supporter quelque
chose qui a changé il y a plus de quinze ans, je comprendrais
bien qu'il n'y investit plus beaucoup d'effort, voire même qu'il
supprime l'option d'ici peu. Qu'on change quelque chose qui a
marché d'une version à l'autre, sans même qu'il y a eu un
avertissement entre-temps, je ne suis pas d'accord. Mais je
reconnais des limites quand même -- au bout de quinze ans, on
pourrait prétendre que les utilisateurs ont eu le temps de faire
l'évolution.


On peut comprendre qu'ils rendent l'option obsolète un jour. Reste
qu'on ne sait pas très bien ce que fait cette option Aujourd'hui ...


--
Fab




Avatar
kanze
Fabien Chêne wrote:
James Kanze writes:


[...]
La documentation de cette option est un peu spartiate, comment
savoir s'il imite un Reisser ou un AT&T ou autre ?


Envoyer un rapport d'erreur ? Si on a une option, et qu'on ne
sait pas ce qu'il fait, c'est bien un défaut, je crois.


Je crois aussi.
A noter que si l'on se réfère aux manuels de GCC-2.95.3, et de
GCC-3.0.4, on a déjà plus de détail :


Ce qui laisse penser qu'ils sont en voie de la supprimer
complètement.

-traditional-cpp

Attempt to support some aspects of traditional C
preprocessors. Specifically:

* Comments convert to nothing at all, rather than to a
space. This allows traditional token concatenation.


C'est du Reisser. (D'après mes souvenirs, le préprocesseur
d'AT&T remplaçait le commentaire par un espace.)

* In a preprocessing directive, the `#' symbol must appear as
the first character of a line.

* Macro arguments are recognized within string constants in a
macro definition (and their values are stringified, though
without additional quote marks, when they appear in such a
context). The preprocessor always considers a string
constant to end at a newline.


Aussi de Reisser. Je suis 100% sûr que ça ne marchait pas avec
le préprocesseur de AT&T. Mais pour être vraiment Reisser, il
faudrait que l'expansion ait lieu dans les constantes de
caractère aussi.

* The predefined macro __STDC__ is not defined when you use
`-traditional', but __GNUC__ is (since the GNU extensions
which __GNUC__ indicates are not affected by
`-traditional'). If you need to write header files that work
differently depending on whether `-traditional' is in use,
by testing both of these predefined macros you can
distinguish four situations: GNU C, traditional GNU C, other
ISO C compilers, and other old C compilers. The predefined
macro __STDC_VERSION__ is also not defined when you use
`-traditional'. See section `Standard Predefined Macros' in
The C Preprocessor, for more discussion of these and other
predefined macros.

* The preprocessor considers a string constant to end at a
newline (unless the newline is escaped with `'). (Without
`-traditional', string constants can contain the newline
character as typed.)


Et ça c'est carrément bizarre. Une constante de chaîne n'a
jamais eu, et n'a pas aujourd'hui, le droit de contenir un saut
à la ligne. C'est une erreur, qui exige une diagnostique. (Et
c'est quelque chose ou le préprocesseur AT&T et la norme, et je
crois aussi Reisser, sont tous d'accord.)

Aussi, g++ (4.1.0) signale bien l'erreur, comme voulu.

Apparemment, au niveau de la concaténation
traditionelle, il tendait à imiter le préprocesseur de Reisser.


C'était la tradition dans le monde du Berkley, je crois.

Par contre, il n'est pas dit que le résultat d'une
concaténation soit nécessairement un token valide.


Ni Reisser ni AT&T n'avait cette restriction. C'est une
innovation du comité C.

Dans les versions suivantes de la documentation de GCC, on a
le droit a plus minimaliste, et au moins le point sur la
concaténation a changé, et dans les versions de GCC que j'ai,
il n'imite plus le preprocesseur de Reisser, le commentaire
est équivalent à un espace.


C-à-d probablement qu'ils considèrent l'option périmée, et
qu'ils préparent à la supprimer.

J'ajouterais que, vue que c'est une hack pour supporter
quelque chose qui a changé il y a plus de quinze ans, je
comprendrais bien qu'il n'y investit plus beaucoup d'effort,
voire même qu'il supprime l'option d'ici peu. Qu'on change
quelque chose qui a marché d'une version à l'autre, sans
même qu'il y a eu un avertissement entre-temps, je ne suis
pas d'accord. Mais je reconnais des limites quand même -- au
bout de quinze ans, on pourrait prétendre que les
utilisateurs ont eu le temps de faire l'évolution.


On peut comprendre qu'ils rendent l'option obsolète un jour.
Reste qu'on ne sait pas très bien ce que fait cette option
Aujourd'hui ...


Peut-être rien ? Peut-être elle n'existe que pour ne pas casser
des fichiers make.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
kanze
Fabien Chêne wrote:

[...]
-traditional-cpp


[...]
On peut comprendre qu'ils rendent l'option obsolète un jour. Reste
qu'on ne sait pas très bien ce que fait cette option Aujourd'hui ...


Suite à un essai rapide, j'ai l'impression que cette option ne
fonctionne pas du tout avec g++, seulement avec gcc. Au moins en
ce qui concerne la remplacement des paramètres dans une chaîne.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
fabien.chene
"kanze" writes:

* In a preprocessing directive, the `#' symbol must appear as
the first character of a line.

* Macro arguments are recognized within string constants in a
macro definition (and their values are stringified, though
without additional quote marks, when they appear in such a
context). The preprocessor always considers a string
constant to end at a newline.


Aussi de Reisser. Je suis 100% sûr que ça ne marchait pas avec
le préprocesseur de AT&T. Mais pour être vraiment Reisser, il
faudrait que l'expansion ait lieu dans les constantes de
caractère aussi.


C'est à dire ?


* The predefined macro __STDC__ is not defined when you use
`-traditional', but __GNUC__ is (since the GNU extensions
which __GNUC__ indicates are not affected by
`-traditional'). If you need to write header files that work
differently depending on whether `-traditional' is in use,
by testing both of these predefined macros you can
distinguish four situations: GNU C, traditional GNU C, other
ISO C compilers, and other old C compilers. The predefined
macro __STDC_VERSION__ is also not defined when you use
`-traditional'. See section `Standard Predefined Macros' in
The C Preprocessor, for more discussion of these and other
predefined macros.

* The preprocessor considers a string constant to end at a
newline (unless the newline is escaped with `'). (Without
`-traditional', string constants can contain the newline
character as typed.)


Et ça c'est carrément bizarre. Une constante de chaîne n'a
jamais eu, et n'a pas aujourd'hui, le droit de contenir un saut
à la ligne. C'est une erreur, qui exige une diagnostique. (Et
c'est quelque chose ou le préprocesseur AT&T et la norme, et je
crois aussi Reisser, sont tous d'accord.)


Il serait intéressant de savoir de quel préprocesseur « old-fashion »
provient ce dernier paragraphe. J'ai du mal à croire qu'ils l'ait
inventé de toute pièce :-/

J'ajouterais que, vue que c'est une hack pour supporter
quelque chose qui a changé il y a plus de quinze ans, je
comprendrais bien qu'il n'y investit plus beaucoup d'effort,
voire même qu'il supprime l'option d'ici peu. Qu'on change
quelque chose qui a marché d'une version à l'autre, sans
même qu'il y a eu un avertissement entre-temps, je ne suis
pas d'accord. Mais je reconnais des limites quand même -- au
bout de quinze ans, on pourrait prétendre que les
utilisateurs ont eu le temps de faire l'évolution.


On peut comprendre qu'ils rendent l'option obsolète un jour.
Reste qu'on ne sait pas très bien ce que fait cette option
Aujourd'hui ...


Peut-être rien ? Peut-être elle n'existe que pour ne pas casser
des fichiers make.


Si c'est le cas, je crois qu'il n'est pas déshonnorant de le
documenter comme « ignoré par compatibilité ». A moins qu'il ne
s'agisse d'une erreur, je crois que c'est ce qu'ils auraient fait.

--
Fab



Avatar
fabien.chene
"kanze" writes:

Fabien Chêne wrote:

[...]
-traditional-cpp


[...]
On peut comprendre qu'ils rendent l'option obsolète un jour. Reste
qu'on ne sait pas très bien ce que fait cette option Aujourd'hui ...


Suite à un essai rapide, j'ai l'impression que cette option ne
fonctionne pas du tout avec g++, seulement avec gcc. Au moins en
ce qui concerne la remplacement des paramètres dans une chaîne.


Un essai rapide pour la concaténation « à la Reisser » sur GCC-3.4.6
me donne un résultat identique avec gcc et g++, en mode traditionnel
-- ça ne concatène pas. C'est bien cela dont tu parles ? Et cela
produit un résultat différent ?

--
Fab


Avatar
kanze
Fabien Chêne wrote:
"kanze" writes:

* In a preprocessing directive, the `#' symbol must appear as
the first character of a line.

* Macro arguments are recognized within string constants in a
macro definition (and their values are stringified, though
without additional quote marks, when they appear in such a
context). The preprocessor always considers a string
constant to end at a newline.


Aussi de Reisser. Je suis 100% sûr que ça ne marchait pas
avec le préprocesseur de AT&T. Mais pour être vraiment
Reisser, il faudrait que l'expansion ait lieu dans les
constantes de caractère aussi.


C'est à dire ?


#define x(a) 'a'

printf( "%cn", x( z ) ) ;

Affiche z, et non a.

[...]
* The preprocessor considers a string constant to end at a
newline (unless the newline is escaped with `'). (Without
`-traditional', string constants can contain the newline
character as typed.)


Et ça c'est carrément bizarre. Une constante de chaîne n'a
jamais eu, et n'a pas aujourd'hui, le droit de contenir un
saut à la ligne. C'est une erreur, qui exige une
diagnostique. (Et c'est quelque chose ou le préprocesseur
AT&T et la norme, et je crois aussi Reisser, sont tous
d'accord.)


Il serait intéressant de savoir de quel préprocesseur «
old-fashion » provient ce dernier paragraphe. J'ai du mal à
croire qu'ils l'ait inventé de toute pièce :-/


Moi non. Gcc a une longue histoire, et au départ, ils ont bien
implémenté leur propre préprocesseur. À une époque d'avant la
norme C. Ils ont bien sûr essayé d'être compatible avec quelque
chose (apparamment Reisser), mais rien ne dit qu'ils n'ont pas
écarté ici ou là, soit par accident, soit parce qu'ils
estimaient mieux faire.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
kanze
Fabien Chêne wrote:
"kanze" writes:

Fabien Chêne wrote:

[...]
-traditional-cpp


[...]
On peut comprendre qu'ils rendent l'option obsolète un jour. Reste
qu'on ne sait pas très bien ce que fait cette option Aujourd'hui ...


Suite à un essai rapide, j'ai l'impression que cette option ne
fonctionne pas du tout avec g++, seulement avec gcc. Au moins en
ce qui concerne la remplacement des paramètres dans une chaîne.


Un essai rapide pour la concaténation « à la Reisser » sur
GCC-3.4.6 me donne un résultat identique avec gcc et g++, en
mode traditionnel -- ça ne concatène pas. C'est bien cela dont
tu parles ? Et cela produit un résultat différent ?


Moi, c'est gcc 4.1.0. Et le programme (C) était:

#include <stdio.h>
#define x(a, b) "a, b"

int
main()
{
printf( "%sn", x( 1, 2 ) ) ;
return 0 ;
}

Compilé avec gcc -traditional-cpp, ça affiche :
1, 2
Compilé avec g++ -traditional-cpp ou gcc sans l'option :
a, b
(ce qui correspond à ce que veulent les normes C et C++).

La documentation de 4.1.1 dit :
Formerly, these options caused GCC to attempt to emulate a
pre-standard C compiler. They are now only supported with
the -E switch. The preprocessor continues to support a
pre-standard mode. See the GNU CPP manual for details.

Je ne sais pas si ça a changé entre 4.1.0 et 4.1.1, mais ce
n'est pas tout à fait ce que je vois avec 4.1.0. (Il y a aussi
une option « -no-integrated-cpp » qui pourrait avoir un
effet.)

De toute façon, la direction de l'évolution est claire, et ça ne
m'étonnerait pas de voir disparaître l'option dans une version
future.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



1 2 3 4