Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

##

14 réponses
Avatar
gpgnews
bonjour
j'aurais voulu comprendre l'utilisation du ##, un exmple:
#define MANGLE(x) (OpenGL::GetCurrent(__FILE__, __LINE__)).##x

merci

10 réponses

1 2
Avatar
Jean-Marc Bourguet
writes:

bonjour
j'aurais voulu comprendre l'utilisation du ##, un exmple:
#define MANGLE(x) (OpenGL::GetCurrent(__FILE__, __LINE__)).##x


Mauvais exemple, je vois mal dans quel cas l'utiliser.

## fusionne les deux symboles qui l'entoure en un seul. Le cas le plus
courant est pour construire des identificateurs sur base d'une racine
passee en parametre.

Exemple simple

#define PUSH(type, value) push_##type(value)

PUSH(int, 5);

equivaut a

push_int(5);

Sans le ##, ce serait equivalent a

push_ int(5);

qui poserait probleme.

(La raison pour laquelle j'ai des doutes sur la pertinence de ton exemple
est que je ne vois pas de symbole commencant par . qu'on ait envie de
construire comme cela d'une part et qui soit utilisable dans ce contexte
d'autre part).

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
espie
In article ,
Jean-Marc Bourguet wrote:
writes:

bonjour
j'aurais voulu comprendre l'utilisation du ##, un exmple:
#define MANGLE(x) (OpenGL::GetCurrent(__FILE__, __LINE__)).##x


Mauvais exemple, je vois mal dans quel cas l'utiliser.

## fusionne les deux symboles qui l'entoure en un seul. Le cas le plus
courant est pour construire des identificateurs sur base d'une racine
passee en parametre.

Exemple simple

#define PUSH(type, value) push_##type(value)

PUSH(int, 5);

equivaut a

push_int(5);

Sans le ##, ce serait equivalent a

push_ int(5);

qui poserait probleme.

(La raison pour laquelle j'ai des doutes sur la pertinence de ton exemple
est que je ne vois pas de symbole commencant par . qu'on ait envie de
construire comme cela d'une part et qui soit utilisable dans ce contexte
d'autre part).


L'exemple est faux, mais j'en ai deja rencontre des comme ca...

Pour bien comprendre ##, il faut voir comment est cense marcher le
compilateur C selon la norme C. Il y a plusieurs phases: decoupage en lexemes
(tokens en anglais), application du preprocesseur, puis du compilateur.

Le truc essentiel, c'est que le preprocesseur est cense agir sur les token,
donc entites syntaxiques a part entiere, il n'y a *que* ## qui permet
de recoller des morceaux.

Par exemple:

#define DOUBLE(a) a/* */a

z DOUBLE(+);

ne fonctionnera pas en C ANSI, puisque le ++ ainsi construit est constitue de
DEUX operateurs + distincts, et non pas d'un operateur ++.

De meme (et c'est plus utile) pour fabriquer un nom de fonction ou variable:

#define FUNC(a, b) a##b


Quelques elements supplementaires:
- en C traditionnel, le preprocesseur travaille sur du texte, et remplace
les commentaires par rien (d'ou le DOUBLE ci-dessus).

- En C ANSI, le preprocesseur travaille sur des lexeme, et remplace un
commentaire par un espace.

- Certaines versions de compilateurs intermediaires (les vieux gcc) ont des
regles intermediaires: ils reconnaissent ## pour indiquer un bete recollage,
mais travaillent avec du texte. Sur ces compilateurs,
#define MANGLE(x) (OpenGL::GetCurrent(__FILE__, __LINE__)).##x
`fonctionnera', mais c'est une erreur. Lors de l'utilisation de cette macro,


un compilateur decent expliquera que .foo (si x vaut foo) n'est pas un lexeme
valide pour le langage C.

Plus clair ?


Avatar
Sylvain
Marc Espie wrote on 21/01/2008 14:44:

#define MANGLE(x) (OpenGL::GetCurrent(__FILE__, __LINE__)).##x
`fonctionnera', mais c'est une erreur. Lors de l'utilisation de cette macro,


un compilateur decent expliquera que .foo (si x vaut foo) n'est pas un lexeme
valide pour le langage C.


pourquoi juste "foo", "MANGLE(foo());" serait valide ... pour peu que
l'instance (inconnue) retournée par ce GetCurrent() propose bien une
telle méthode.

Sylvain.



Avatar
espie
In article <4794b148$0$866$,
Sylvain wrote:
Marc Espie wrote on 21/01/2008 14:44:

#define MANGLE(x) (OpenGL::GetCurrent(__FILE__, __LINE__)).##x
`fonctionnera', mais c'est une erreur. Lors de l'utilisation de cette macro,


un compilateur decent expliquera que .foo (si x vaut foo) n'est pas un lexeme
valide pour le langage C.


pourquoi juste "foo", "MANGLE(foo());" serait valide ... pour peu que
l'instance (inconnue) retournée par ce GetCurrent() propose bien une
telle méthode.


Pas plus valide. Tu essaies toujours de recoller des choses qui ne vont
pas former un seul token.




Avatar
Sylvain
Marc Espie wrote on 21/01/2008 15:52:
In article <4794b148$0$866$,
Sylvain wrote:
Marc Espie wrote on 21/01/2008 14:44:
#define MANGLE(x) (OpenGL::GetCurrent(__FILE__, __LINE__)).##x
`fonctionnera', mais c'est une erreur. Lors de l'utilisation de cette macro,


un compilateur decent expliquera que .foo (si x vaut foo) n'est pas un lexeme
valide pour le langage C.
pourquoi juste "foo", "MANGLE(foo());" serait valide ... pour peu que

l'instance (inconnue) retournée par ce GetCurrent() propose bien une
telle méthode.


Pas plus valide. Tu essaies toujours de recoller des choses qui ne vont
pas former un seul token.


?!? j'avais oublié le "valide pour le language C" dans ton affirmation.
en C, en effet, un appel comme "instance.foo()" n'est pas valide (une
porte ouverte), mais pour ce forum ce serait bien valide.

Sylvain.





Avatar
espie
In article <4794b290$0$843$,
Sylvain wrote:
Marc Espie wrote on 21/01/2008 15:52:
In article <4794b148$0$866$,
Sylvain wrote:
Marc Espie wrote on 21/01/2008 14:44:
#define MANGLE(x) (OpenGL::GetCurrent(__FILE__, __LINE__)).##x
`fonctionnera', mais c'est une erreur. Lors de l'utilisation de cette macro,


un compilateur decent expliquera que .foo (si x vaut foo) n'est pas
un lexeme



valide pour le langage C.
pourquoi juste "foo", "MANGLE(foo());" serait valide ... pour peu que

l'instance (inconnue) retournée par ce GetCurrent() propose bien une
telle méthode.


Pas plus valide. Tu essaies toujours de recoller des choses qui ne vont
pas former un seul token.


?!? j'avais oublié le "valide pour le language C" dans ton affirmation.
en C, en effet, un appel comme "instance.foo()" n'est pas valide (une
porte ouverte), mais pour ce forum ce serait bien valide.

Sylvain.


C'est toujours pas plus valide. Le C++ standard utilise les memes regles
que le C pour le preprocesseur, et tu n'as pas plus le droit de recoller
des tokens pour fabriquer un truc qui n'en es pas un.

Il suffit d'un
#define MANGLE(x) (OpenGL::GetCurrent(__FILE__, __LINE__)).x
`fonctionnera', mais c'est une erreur. Lors de l'utilisation de cette macro,
un compilateur decent expliquera que .foo (si x vaut foo) n'est pas
un lexeme



valide pour le langage C.
pourquoi juste "foo", "MANGLE(foo());" serait valide ... pour peu que

l'instance (inconnue) retournée par ce GetCurrent() propose bien une
telle méthode.


Pas plus valide. Tu essaies toujours de recoller des choses qui ne vont
pas former un seul token.


?!? j'avais oublié le "valide pour le language C" dans ton affirmation.
en C, en effet, un appel comme "instance.foo()" n'est pas valide (une
porte ouverte), mais pour ce forum ce serait bien valide.

Sylvain.


C'est toujours pas plus valide. Le C++ standard utilise les memes regles
que le C pour le preprocesseur, et tu n'as pas plus le droit de recoller
des tokens pour fabriquer un truc qui n'en es pas un.

Si tu veux faire ce genre de manip, la bonne macro est tout simplement:
#define MANGLE(x) (OpenGL::GetCurrent(__FILE__, __LINE__)).x

Il n'y a pas besoin de recoller des morceaux: .x est parfaitement legal
et correct.

Qu'on soit en C ou en C++ n'a absolument aucune importance. C++ inclut le
langage C dans sa description, et les implementations auxquelles je me
refere partagent en general le preprocesseur entre C et C++.

Ca a conduit a un certain nombre de problemes avant que le preprocesseur
soit remplace par un preprocesseur ansi...

Le seul probleme specifique au C++, ca serait le traitement du //.

Les preprocesseurs pre-C99 ne sont pas oblies de le reconnaitre comme
commentaire, et ca peut donner des situations exotiques, tels que:

#include "monentete.h" // et hop, un commentaire C++ que le pp DOIT traiter.

qui a de bonnes chances de faire n'importe quoi...






Avatar
James Kanze
On Jan 21, 2:44 pm, (Marc Espie) wrote:
In article ,
Jean-Marc Bourguet wrote:
writes:



[...]
Pour bien comprendre ##, il faut voir comment est cense
marcher le compilateur C selon la norme C. Il y a plusieurs
phases: decoupage en lexemes (tokens en anglais), application
du preprocesseur, puis du compilateur.

Le truc essentiel, c'est que le preprocesseur est cense agir sur les token ,
donc entites syntaxiques a part entiere, il n'y a *que* ## qui permet
de recoller des morceaux.


[...]
Quelques elements supplementaires:
- en C traditionnel, le preprocesseur travaille sur du texte, et remplace
les commentaires par rien (d'ou le DOUBLE ci-dessus).

- En C ANSI, le preprocesseur travaille sur des lexeme, et remplace un
commentaire par un espace.


Plus précisement, la norme C a été soigneusement formulée de
façon à permettre le preprocesseur de travailler sur des
lexèmes. Ou du texte, selon la volenté de l'implémentation.

- Certaines versions de compilateurs intermediaires (les vieux gcc) ont de s
regles intermediaires: ils reconnaissent ## pour indiquer un bete recollag e,
mais travaillent avec du texte. Sur ces compilateurs,
#define MANGLE(x) (OpenGL::GetCurrent(__FILE__, __LINE__)).##x
`fonctionnera', mais c'est une erreur.



C'est toujours une erreur. Un comportement indéfin.

Dans la pratique, ça fonctionnera encore avec pas mal de
compilateurs. Les auteurs de la norme ont voulu permettre
l'utilisation des lexèmes (qui en principe rendra le compilateur
plus rapide). Mais la plupart des vendeurs n'ont pas voulu
casser du code qui fonctionnait avant.

Lors de l'utilisation de cette macro, un compilateur decent
expliquera que .foo (si x vaut foo) n'est pas un lexeme valide
pour le langage C.


S'il n'y avait que ça. (Le mieux, évidemment, serait un
avertissement « anachronism », si cher à Sun. Mais je doute que
Sun CC donne même un avertissement ici.)

--
James Kanze (GABI Software) email:
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
On Jan 21, 3:56 pm, Sylvain wrote:
Marc Espie wrote on 21/01/2008 15:52:

In article <4794b148$0$866$,
Sylvain wrote:
Marc Espie wrote on 21/01/2008 14:44:
#define MANGLE(x) (OpenGL::GetCurrent(__FILE__, __LINE__)).##x
`fonctionnera', mais c'est une erreur. Lors de


l'utilisation de cette macro, un compilateur decent
expliquera que .foo (si x vaut foo) n'est pas un lexeme
valide pour le langage C.
pourquoi juste "foo", "MANGLE(foo());" serait valide ... pour peu que

l'instance (inconnue) retournée par ce GetCurrent() propose bien une
telle méthode.


Pas plus valide. Tu essaies toujours de recoller des choses qui ne vont
pas former un seul token.


?!? j'avais oublié le "valide pour le language C" dans ton affirmation.
en C, en effet, un appel comme "instance.foo()" n'est pas valide (une
porte ouverte), mais pour ce forum ce serait bien valide.


À cet égard, égard, le C++ est 100% compatible avec le C.
Autant que je sache, la seule différence entre le préprocesseur
C90 et le préprocesseur C++, c'est que le C++ reconnaît les
commentaires //. En tout cas, le texte du §16.3.3 de l'ISO
14882:1998 est exactement identique à §6.8.3.3 de l'ISO
9899:1990. En particular, le paragraphe 3, qui dit :

For both object-like and function-like macro
invocations, before the replacement list is reexamined
for more macro names to replace, each instance of a ##
preprocessing token in the replacement liest (not from
an argument) is deleted and the preceding preprocessing
token is concatenated with the following preprocessing
token. __If the result is not a valid preprocessing
token, the behavior is undefined.__ The resulting token
is available for further macro replacement. The order
of evaluation of ## operators is unspecified.

L'intention ici (comme par ailleurs), c'est de permettre au
préprocesseur de travailler directement avec les lexèmes (la
"tokenized source"), plutôt qu'avec les chaînes de
caractères. Sauf qu'en fait, c'est assez difficile à
comprendre ce que veut dire « the preceding preprocessing
token is concatenated with the following preprocessing
token » si on ne parle pas de texte.

Dans la pratique, les compilateurs travaillent prèsque tous
avec du texte -- même dans le cas de g++, ça ne m'étonnerait
pas qu'à la base, il travaille avec du texte, et ne fait
qu'une vérification supplémentaire exprès pour emmerder le
programmeur/détecter encore des cas d'erreurs potentielles
(à choisir, selon que la quantité du code existant que tu as
à maintenir). L'idée de permettre de travailler avec les
lexèmes date d'une époque où la phase lexique était la plus
chère en temps CPU du compilateur.

--
James Kanze (GABI Software) email:
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
Sylvain
James Kanze wrote on 21/01/2008 21:15:

?!? j'avais oublié le "valide pour le language C" dans ton affirmation.
en C, en effet, un appel comme "instance.foo()" n'est pas valide (une
porte ouverte), mais pour ce forum ce serait bien valide.


À cet égard, égard, le C++ est 100% compatible avec le C.
Autant que je sache, la seule différence entre le préprocesseur
C90 et le préprocesseur C++, c'est que le C++ reconnaît les
commentaires //


c'est clairement ce à quoi je m'attends!
ie je n'attends pas "n'importe quoi" d'un pp C, mais bien une erreur.

[...]
Dans la pratique, les compilateurs travaillent prèsque tous
avec du texte -- même dans le cas de g++, ça ne m'étonnerait
pas qu'à la base, il travaille avec du texte, et ne fait
qu'une vérification supplémentaire exprès pour emmerder le
programmeur/détecter encore des cas d'erreurs potentielles


c'est aussi mon expérience et elle permet parfaitement de préprocesser
le MANGLE proposé ... mais je suis prêt à entendre que Marc a raison en
théorie ;)

Sylvain.


Avatar
espie
In article <479507be$0$868$,
Sylvain wrote:
James Kanze wrote on 21/01/2008 21:15:

[...]
Dans la pratique, les compilateurs travaillent prèsque tous
avec du texte -- même dans le cas de g++, ça ne m'étonnerait
pas qu'à la base, il travaille avec du texte, et ne fait
qu'une vérification supplémentaire exprès pour emmerder le
programmeur/détecter encore des cas d'erreurs potentielles



Non, les versions recentes de GCC ont integre le preprocesseur dans
le compilateur, et travaillent *reellement* sur des lexemes.

c'est aussi mon expérience et elle permet parfaitement de préprocesser
le MANGLE proposé ... mais je suis prêt à entendre que Marc a raison en
théorie ;)


Marc a non seulement raison en theorie, j'ai aussi raison en pratique.

La vraie raison pour laquelle j'en sais autant sur ces errements du
preprocesseur, c'est parce que j'ai eu a me coltiner la correction
de ce genre de problemes (utilisation incorrecte de ##) dans OpenBSD
pour pouvoir mettre a jour le compilateur a une version recente de GCC...

Donc je peux te garantir qu'il rale sur des ## mal places, et pour avoir
regarde le code du preprocesseur lui-meme, je peux aussi te garantir
qu'il essaie de convertir le code en lexemes des le preprocesseur.


1 2