wrote:Ou est-ce que l'opérateur de stringification met des "..." ?
L'opérateur de stringification génère un token de type string
literal. L'autre façon d'obtenir un string literal, évidemment,
c'est de mettre le texte entre des "...". Sauf que dans le contexte
d'un include, mettre le texte entre des "..." ne fait pas un string
literal.
C'est une distinction très importante. Par exemple :
#include "a-b" // défini par l'implémentation,
// éventuellement illégal
char const a[] = "a-b" ; // défini par la norme.
La distinction est même très réele, dans des implémentations
existantes : sous Windows, "n" est bien une séquence de deux
caractères dans un q-char-sequence, mais non dans un string literal.
Effectivement. Les linges suivantes compilent chez moi avec gcc 3.3.1
CygWin, à condition que le fichier "c: tbn.h" existe :
#define STR(x) #x
#define X STR(c: tbn.h)
#include X
char const c[] = X;
(sizeof c == 9)
Je ne suis pas sûr que cela soit le comportement mandaté par 16.3.2/2
et 16.2/4+3
kanze@gabi-soft.fr wrote:
Ou est-ce que l'opérateur de stringification met des "..." ?
L'opérateur de stringification génère un token de type string
literal. L'autre façon d'obtenir un string literal, évidemment,
c'est de mettre le texte entre des "...". Sauf que dans le contexte
d'un include, mettre le texte entre des "..." ne fait pas un string
literal.
C'est une distinction très importante. Par exemple :
#include "a-b" // défini par l'implémentation,
// éventuellement illégal
char const a[] = "a-b" ; // défini par la norme.
La distinction est même très réele, dans des implémentations
existantes : sous Windows, "n" est bien une séquence de deux
caractères dans un q-char-sequence, mais non dans un string literal.
Effectivement. Les linges suivantes compilent chez moi avec gcc 3.3.1
CygWin, à condition que le fichier "c: tbn.h" existe :
#define STR(x) #x
#define X STR(c: tbn.h)
#include X
char const c[] = X;
(sizeof c == 9)
Je ne suis pas sûr que cela soit le comportement mandaté par 16.3.2/2
et 16.2/4+3
wrote:Ou est-ce que l'opérateur de stringification met des "..." ?
L'opérateur de stringification génère un token de type string
literal. L'autre façon d'obtenir un string literal, évidemment,
c'est de mettre le texte entre des "...". Sauf que dans le contexte
d'un include, mettre le texte entre des "..." ne fait pas un string
literal.
C'est une distinction très importante. Par exemple :
#include "a-b" // défini par l'implémentation,
// éventuellement illégal
char const a[] = "a-b" ; // défini par la norme.
La distinction est même très réele, dans des implémentations
existantes : sous Windows, "n" est bien une séquence de deux
caractères dans un q-char-sequence, mais non dans un string literal.
Effectivement. Les linges suivantes compilent chez moi avec gcc 3.3.1
CygWin, à condition que le fichier "c: tbn.h" existe :
#define STR(x) #x
#define X STR(c: tbn.h)
#include X
char const c[] = X;
(sizeof c == 9)
Je ne suis pas sûr que cela soit le comportement mandaté par 16.3.2/2
et 16.2/4+3
writes:
[...]
| > | Ce qui ne va pas sans poser des problèmes dans la définition de
| > | l'opérateur # -- on est amené à parler de l'« orthographe
| > | original », par exemple.
| > | Je sais qu'à l'époque où la norme C était tout neuf, j'ai eu des
| > | discussions avec certains membres du comité -- je ne me rappelle
| > | plus qui, et que ce sont eux qui m'ont dit que la forme proposée
| > | par Jean-Marc était illégal, et que la bonne forme était celui
| > | du premier posting.
| > Peux-tu articuler clairement pourquoi cette solution du premier
| > posting est valide ?
| Je suis tempté à dire que c'est pour les mêmes raisons que la
| solution que tu préconsises est valide.
Reprenons le code de départ.
#define PATH_CONTROLLER_JOYPAD <controller/src/##TARGET##/Joypad.h>
#include PATH_CONTROLLER_JOYPAD
La première ligne est une suite de pp-tokens comme suit :
{#}{define} {PATH_CONTROLLER_JOYPAD} {<}{controller}{/}{src}{/}{##}{TARGET}{##}{/}{Joypad}{.}{h}{>}
Le traitement de cette directive tombe sous le coup de 16.3.3/3 :
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 list (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.
Donc, avant même que la subtitution se produise (qui donnerait TARGET
-> PS2), la norme demande que {/} et {TARGET} soit concatenés, ce qui
donnerait {/TARGET} qui ne peut être un pp-otken valide.
| En fait, il n'y a rien dans la norme qui l'interdit.
Voir ci-dessus.
| Mais je crois que toi aussi, il y a des passages que tu as sauté
| dans ce que j'ai écrit. Dans la contexte de l'expansion d'un
| include, si une suite de caractères comme « x/y » est un token valid
| ou non dépend de l'implémentation -- mais sous Unix, tous les
| compilateurs que je connais (y compris g++ 3.4.0 dans le cas
| général) l'accepte comme h-char-sequence (et dans la contexte d'une
| include, après un <, le *seul* token légal du préprocesseur, c'est
| un h-char-sequence).
Je crois que tu confonds deux choses distinctes :
(1) ce que fait l'opérateur ## ; et
(2) et une suite de pp-tokens, comme {x}{/}{y}, dans un context
comme j'ai cité dans le précédent mail.
La norme demande explicitement que
#include <x/y>
soit pp-tokeniser comme
{#}{include} {<x/y>}
alors que
#define PATH <x/y>
sera pp-tokeniser comme
{#}{define} {PATH} {<}{x}{/}{y}{>}
| Note bien §2.1/3 : « The process of dividing a source file's
| characters into preprocessing tokens is context-dependent. » On
| n'est pas n'importe où, on est dans une contexte où le seul token du
| préprocesseur permis est un h-char-sequence. Alors, si le résultat
| de ## n'est pas une h-char-sequence valide, le code est illégal --
| s'il l'est, le code est légal. Évidemment, ce que c'est qu'un
| h-char-sequence dépend de l'implémentation. Mais il doit être
| documenté, et il doit être pareil partout. Si on accepte « #include
| <x/y> », on est obligé dans cette contexte d'accepter x / y comme
| résultat de ##.
Je crois que tu vas trop vite dans ton raisonnement et que tu tombes
dan un trap. Par exemple, la ligne
#include <x/y>
est composée de
{#}{include} {<x/y>}
alors quelque chose comme
#define PATH <x/y>
donne
{#}{define} {PATH} {<}{x}{/}{y}{>}
c'est-à-dire le context de #include demane que si on voit '<' ou '"',
on prenne la plus longue chaîne possible pour faire un header-name.
Alors que dans le cas de #define, on tokenise et si on écrit quelque
chose
#include PATH
il y a expansion en
{#}{include} {<}{x}{/}{y}{>}
Note bien qu'ici, '<' apparaît comme un pp-token en soi -- et non
comme partie de chaîne de caractères qui ferait un header-name -- et
c'est seulement après cela que la norme demande que la suite de
pp-tokens entre les tokens {<} et {>} soit collectée pour former un
header-name (la méthode, i.e. comment c'est fabriqué dépend de
l'implémentation).
Note bien, qu'il y a d'abord substitutions de *pp-tokens* et après
collection. Pendant cette substitution, il n'y a pas de notion de
h-char.
| Il y a une deuxième chose qui me chagrine un peu, si on accepte ton
| interprétation. Prenons l'exemple dans la norme, qui génère « #include
| "vers2.h" ». Si j'ai bien compris ton argumentation, l'exemple serait
| illégal si la version était « 2.2 », plutôt que « 2 », parce que le
| résultat de ## dans l'expansion de INCFILE n'est pas un token légal du
| préprocesseur (et la stringisation ne s'appliquera que plus tard).
Reproduisons l'exemple de la norme pour voir de quoi on parle.
16.3.5/6
#define str(s) # s
#define xstr(s) str(s)
#define debug(s, t) printf("x" # s "= %d, x" # t "= %s",
x ## s, x ## t)
#define INCFILE(n) vers ## n /* from previous #include example */
#define glue(a, b) a ## b
#define xglue(a, b) glue(a, b)
#define HIGHLOW "hello"
#define LOW LOW ", world"
debug(1, 2);
fputs(str(strncmp("abc d", "abc", 4 ) /* this goes away */
== 0) str(: @n), s);
#include xstr(INCFILE(2).h)
glue(HIGH, LOW);
xglue(HIGH, LOW)
Si tu écris INCFILE(2.2) au lieu de INCFILE(2), tu tombes sous le coup
de 16.3.3/2
If, in the replacement list, a parameter is immediately preceded
or followed by a ## preprocessing token, the parameter is replaced
by the corresponding argument s preprocessing token sequence.
Donc, l'expansion de la macro INCFILE donne
{vers}{##}{2.2}
ce qui après concaténation ressemble à {vers2.2} qui n'est pas un
pp-token valide.
Note bien que l'exemple de la norme n'est pas
#include xstr(INCFILE(2.h))
qui produirait un pp-token invalde lors de la concaténation, mais bien
#include xstr(INCFILE(2).h)
de sorte la concatération se passe bien et la stringification fasse
proprement ce qu'il doit faire.
| D'abord, est-ce que j'ai bien compris ton argumentation, et que
| c'est juste.
Oui.
| Et deuxièmement, indépendamment de ce que dit la norme, est-ce que
| c'est une contrainte raisonable ?
De mon point ce vue, cela facilite le traitement -- si on se base sur
une subtsitution de tokens. (Si on fait une substituion sur du texte,
cela n'est pas nécessaire).
Concrêtement, l'idée est qu'on prend deux tokens et on les remplace
par un autre. On peut imaginer une routine dont le propos est de
valider une suite de caractères comme un pp-token ou non. Donc on
prend les deux tokens, on assemble leurs orthographes et on demande à
la routine si c'est un pp-token ou non. C'est simple, stupide et
efficace. L'autre alternative serait de redemander un redécoupage en
suite de tokens -- c'est le procédé traditionnel, par exemple gcc
-traditional.
| En autres mots, est-ce que la solution proposée par Jean-Marc doit
| échouer si le nom du cible (TARGET) était PS-2, à la place de PS2 ?
Non, la solution proposée par Jean-Marc marche même si TARGET était
PS-2 à la place de PS2. La raison est qu'il n'utilise pas l'opérateur
## qui pose de problème dans le cas de INCFILE(2.2).
| (Et en passant, je crois que la version « correcte » de ce qu'il
| voulait faire serait :
| #define PATH_CONTROLLER_JOYPAD <controller##/##src##/##TARGET##/##Joypad.h>
Non, ce n'est pas correcte pour la même raison qu'avant : quand tu
concatènes {controller} et {/}, tu n'obtiens pas un pp-token valide.
kanze@gabi-soft.fr writes:
[...]
| > | Ce qui ne va pas sans poser des problèmes dans la définition de
| > | l'opérateur # -- on est amené à parler de l'« orthographe
| > | original », par exemple.
| > | Je sais qu'à l'époque où la norme C était tout neuf, j'ai eu des
| > | discussions avec certains membres du comité -- je ne me rappelle
| > | plus qui, et que ce sont eux qui m'ont dit que la forme proposée
| > | par Jean-Marc était illégal, et que la bonne forme était celui
| > | du premier posting.
| > Peux-tu articuler clairement pourquoi cette solution du premier
| > posting est valide ?
| Je suis tempté à dire que c'est pour les mêmes raisons que la
| solution que tu préconsises est valide.
Reprenons le code de départ.
#define PATH_CONTROLLER_JOYPAD <controller/src/##TARGET##/Joypad.h>
#include PATH_CONTROLLER_JOYPAD
La première ligne est une suite de pp-tokens comme suit :
{#}{define} {PATH_CONTROLLER_JOYPAD} {<}{controller}{/}{src}{/}{##}{TARGET}{##}{/}{Joypad}{.}{h}{>}
Le traitement de cette directive tombe sous le coup de 16.3.3/3 :
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 list (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.
Donc, avant même que la subtitution se produise (qui donnerait TARGET
-> PS2), la norme demande que {/} et {TARGET} soit concatenés, ce qui
donnerait {/TARGET} qui ne peut être un pp-otken valide.
| En fait, il n'y a rien dans la norme qui l'interdit.
Voir ci-dessus.
| Mais je crois que toi aussi, il y a des passages que tu as sauté
| dans ce que j'ai écrit. Dans la contexte de l'expansion d'un
| include, si une suite de caractères comme « x/y » est un token valid
| ou non dépend de l'implémentation -- mais sous Unix, tous les
| compilateurs que je connais (y compris g++ 3.4.0 dans le cas
| général) l'accepte comme h-char-sequence (et dans la contexte d'une
| include, après un <, le *seul* token légal du préprocesseur, c'est
| un h-char-sequence).
Je crois que tu confonds deux choses distinctes :
(1) ce que fait l'opérateur ## ; et
(2) et une suite de pp-tokens, comme {x}{/}{y}, dans un context
comme j'ai cité dans le précédent mail.
La norme demande explicitement que
#include <x/y>
soit pp-tokeniser comme
{#}{include} {<x/y>}
alors que
#define PATH <x/y>
sera pp-tokeniser comme
{#}{define} {PATH} {<}{x}{/}{y}{>}
| Note bien §2.1/3 : « The process of dividing a source file's
| characters into preprocessing tokens is context-dependent. » On
| n'est pas n'importe où, on est dans une contexte où le seul token du
| préprocesseur permis est un h-char-sequence. Alors, si le résultat
| de ## n'est pas une h-char-sequence valide, le code est illégal --
| s'il l'est, le code est légal. Évidemment, ce que c'est qu'un
| h-char-sequence dépend de l'implémentation. Mais il doit être
| documenté, et il doit être pareil partout. Si on accepte « #include
| <x/y> », on est obligé dans cette contexte d'accepter x / y comme
| résultat de ##.
Je crois que tu vas trop vite dans ton raisonnement et que tu tombes
dan un trap. Par exemple, la ligne
#include <x/y>
est composée de
{#}{include} {<x/y>}
alors quelque chose comme
#define PATH <x/y>
donne
{#}{define} {PATH} {<}{x}{/}{y}{>}
c'est-à-dire le context de #include demane que si on voit '<' ou '"',
on prenne la plus longue chaîne possible pour faire un header-name.
Alors que dans le cas de #define, on tokenise et si on écrit quelque
chose
#include PATH
il y a expansion en
{#}{include} {<}{x}{/}{y}{>}
Note bien qu'ici, '<' apparaît comme un pp-token en soi -- et non
comme partie de chaîne de caractères qui ferait un header-name -- et
c'est seulement après cela que la norme demande que la suite de
pp-tokens entre les tokens {<} et {>} soit collectée pour former un
header-name (la méthode, i.e. comment c'est fabriqué dépend de
l'implémentation).
Note bien, qu'il y a d'abord substitutions de *pp-tokens* et après
collection. Pendant cette substitution, il n'y a pas de notion de
h-char.
| Il y a une deuxième chose qui me chagrine un peu, si on accepte ton
| interprétation. Prenons l'exemple dans la norme, qui génère « #include
| "vers2.h" ». Si j'ai bien compris ton argumentation, l'exemple serait
| illégal si la version était « 2.2 », plutôt que « 2 », parce que le
| résultat de ## dans l'expansion de INCFILE n'est pas un token légal du
| préprocesseur (et la stringisation ne s'appliquera que plus tard).
Reproduisons l'exemple de la norme pour voir de quoi on parle.
16.3.5/6
#define str(s) # s
#define xstr(s) str(s)
#define debug(s, t) printf("x" # s "= %d, x" # t "= %s",
x ## s, x ## t)
#define INCFILE(n) vers ## n /* from previous #include example */
#define glue(a, b) a ## b
#define xglue(a, b) glue(a, b)
#define HIGHLOW "hello"
#define LOW LOW ", world"
debug(1, 2);
fputs(str(strncmp("abc d", "abc", 4 ) /* this goes away */
== 0) str(: @n), s);
#include xstr(INCFILE(2).h)
glue(HIGH, LOW);
xglue(HIGH, LOW)
Si tu écris INCFILE(2.2) au lieu de INCFILE(2), tu tombes sous le coup
de 16.3.3/2
If, in the replacement list, a parameter is immediately preceded
or followed by a ## preprocessing token, the parameter is replaced
by the corresponding argument s preprocessing token sequence.
Donc, l'expansion de la macro INCFILE donne
{vers}{##}{2.2}
ce qui après concaténation ressemble à {vers2.2} qui n'est pas un
pp-token valide.
Note bien que l'exemple de la norme n'est pas
#include xstr(INCFILE(2.h))
qui produirait un pp-token invalde lors de la concaténation, mais bien
#include xstr(INCFILE(2).h)
de sorte la concatération se passe bien et la stringification fasse
proprement ce qu'il doit faire.
| D'abord, est-ce que j'ai bien compris ton argumentation, et que
| c'est juste.
Oui.
| Et deuxièmement, indépendamment de ce que dit la norme, est-ce que
| c'est une contrainte raisonable ?
De mon point ce vue, cela facilite le traitement -- si on se base sur
une subtsitution de tokens. (Si on fait une substituion sur du texte,
cela n'est pas nécessaire).
Concrêtement, l'idée est qu'on prend deux tokens et on les remplace
par un autre. On peut imaginer une routine dont le propos est de
valider une suite de caractères comme un pp-token ou non. Donc on
prend les deux tokens, on assemble leurs orthographes et on demande à
la routine si c'est un pp-token ou non. C'est simple, stupide et
efficace. L'autre alternative serait de redemander un redécoupage en
suite de tokens -- c'est le procédé traditionnel, par exemple gcc
-traditional.
| En autres mots, est-ce que la solution proposée par Jean-Marc doit
| échouer si le nom du cible (TARGET) était PS-2, à la place de PS2 ?
Non, la solution proposée par Jean-Marc marche même si TARGET était
PS-2 à la place de PS2. La raison est qu'il n'utilise pas l'opérateur
## qui pose de problème dans le cas de INCFILE(2.2).
| (Et en passant, je crois que la version « correcte » de ce qu'il
| voulait faire serait :
| #define PATH_CONTROLLER_JOYPAD <controller##/##src##/##TARGET##/##Joypad.h>
Non, ce n'est pas correcte pour la même raison qu'avant : quand tu
concatènes {controller} et {/}, tu n'obtiens pas un pp-token valide.
writes:
[...]
| > | Ce qui ne va pas sans poser des problèmes dans la définition de
| > | l'opérateur # -- on est amené à parler de l'« orthographe
| > | original », par exemple.
| > | Je sais qu'à l'époque où la norme C était tout neuf, j'ai eu des
| > | discussions avec certains membres du comité -- je ne me rappelle
| > | plus qui, et que ce sont eux qui m'ont dit que la forme proposée
| > | par Jean-Marc était illégal, et que la bonne forme était celui
| > | du premier posting.
| > Peux-tu articuler clairement pourquoi cette solution du premier
| > posting est valide ?
| Je suis tempté à dire que c'est pour les mêmes raisons que la
| solution que tu préconsises est valide.
Reprenons le code de départ.
#define PATH_CONTROLLER_JOYPAD <controller/src/##TARGET##/Joypad.h>
#include PATH_CONTROLLER_JOYPAD
La première ligne est une suite de pp-tokens comme suit :
{#}{define} {PATH_CONTROLLER_JOYPAD} {<}{controller}{/}{src}{/}{##}{TARGET}{##}{/}{Joypad}{.}{h}{>}
Le traitement de cette directive tombe sous le coup de 16.3.3/3 :
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 list (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.
Donc, avant même que la subtitution se produise (qui donnerait TARGET
-> PS2), la norme demande que {/} et {TARGET} soit concatenés, ce qui
donnerait {/TARGET} qui ne peut être un pp-otken valide.
| En fait, il n'y a rien dans la norme qui l'interdit.
Voir ci-dessus.
| Mais je crois que toi aussi, il y a des passages que tu as sauté
| dans ce que j'ai écrit. Dans la contexte de l'expansion d'un
| include, si une suite de caractères comme « x/y » est un token valid
| ou non dépend de l'implémentation -- mais sous Unix, tous les
| compilateurs que je connais (y compris g++ 3.4.0 dans le cas
| général) l'accepte comme h-char-sequence (et dans la contexte d'une
| include, après un <, le *seul* token légal du préprocesseur, c'est
| un h-char-sequence).
Je crois que tu confonds deux choses distinctes :
(1) ce que fait l'opérateur ## ; et
(2) et une suite de pp-tokens, comme {x}{/}{y}, dans un context
comme j'ai cité dans le précédent mail.
La norme demande explicitement que
#include <x/y>
soit pp-tokeniser comme
{#}{include} {<x/y>}
alors que
#define PATH <x/y>
sera pp-tokeniser comme
{#}{define} {PATH} {<}{x}{/}{y}{>}
| Note bien §2.1/3 : « The process of dividing a source file's
| characters into preprocessing tokens is context-dependent. » On
| n'est pas n'importe où, on est dans une contexte où le seul token du
| préprocesseur permis est un h-char-sequence. Alors, si le résultat
| de ## n'est pas une h-char-sequence valide, le code est illégal --
| s'il l'est, le code est légal. Évidemment, ce que c'est qu'un
| h-char-sequence dépend de l'implémentation. Mais il doit être
| documenté, et il doit être pareil partout. Si on accepte « #include
| <x/y> », on est obligé dans cette contexte d'accepter x / y comme
| résultat de ##.
Je crois que tu vas trop vite dans ton raisonnement et que tu tombes
dan un trap. Par exemple, la ligne
#include <x/y>
est composée de
{#}{include} {<x/y>}
alors quelque chose comme
#define PATH <x/y>
donne
{#}{define} {PATH} {<}{x}{/}{y}{>}
c'est-à-dire le context de #include demane que si on voit '<' ou '"',
on prenne la plus longue chaîne possible pour faire un header-name.
Alors que dans le cas de #define, on tokenise et si on écrit quelque
chose
#include PATH
il y a expansion en
{#}{include} {<}{x}{/}{y}{>}
Note bien qu'ici, '<' apparaît comme un pp-token en soi -- et non
comme partie de chaîne de caractères qui ferait un header-name -- et
c'est seulement après cela que la norme demande que la suite de
pp-tokens entre les tokens {<} et {>} soit collectée pour former un
header-name (la méthode, i.e. comment c'est fabriqué dépend de
l'implémentation).
Note bien, qu'il y a d'abord substitutions de *pp-tokens* et après
collection. Pendant cette substitution, il n'y a pas de notion de
h-char.
| Il y a une deuxième chose qui me chagrine un peu, si on accepte ton
| interprétation. Prenons l'exemple dans la norme, qui génère « #include
| "vers2.h" ». Si j'ai bien compris ton argumentation, l'exemple serait
| illégal si la version était « 2.2 », plutôt que « 2 », parce que le
| résultat de ## dans l'expansion de INCFILE n'est pas un token légal du
| préprocesseur (et la stringisation ne s'appliquera que plus tard).
Reproduisons l'exemple de la norme pour voir de quoi on parle.
16.3.5/6
#define str(s) # s
#define xstr(s) str(s)
#define debug(s, t) printf("x" # s "= %d, x" # t "= %s",
x ## s, x ## t)
#define INCFILE(n) vers ## n /* from previous #include example */
#define glue(a, b) a ## b
#define xglue(a, b) glue(a, b)
#define HIGHLOW "hello"
#define LOW LOW ", world"
debug(1, 2);
fputs(str(strncmp("abc d", "abc", 4 ) /* this goes away */
== 0) str(: @n), s);
#include xstr(INCFILE(2).h)
glue(HIGH, LOW);
xglue(HIGH, LOW)
Si tu écris INCFILE(2.2) au lieu de INCFILE(2), tu tombes sous le coup
de 16.3.3/2
If, in the replacement list, a parameter is immediately preceded
or followed by a ## preprocessing token, the parameter is replaced
by the corresponding argument s preprocessing token sequence.
Donc, l'expansion de la macro INCFILE donne
{vers}{##}{2.2}
ce qui après concaténation ressemble à {vers2.2} qui n'est pas un
pp-token valide.
Note bien que l'exemple de la norme n'est pas
#include xstr(INCFILE(2.h))
qui produirait un pp-token invalde lors de la concaténation, mais bien
#include xstr(INCFILE(2).h)
de sorte la concatération se passe bien et la stringification fasse
proprement ce qu'il doit faire.
| D'abord, est-ce que j'ai bien compris ton argumentation, et que
| c'est juste.
Oui.
| Et deuxièmement, indépendamment de ce que dit la norme, est-ce que
| c'est une contrainte raisonable ?
De mon point ce vue, cela facilite le traitement -- si on se base sur
une subtsitution de tokens. (Si on fait une substituion sur du texte,
cela n'est pas nécessaire).
Concrêtement, l'idée est qu'on prend deux tokens et on les remplace
par un autre. On peut imaginer une routine dont le propos est de
valider une suite de caractères comme un pp-token ou non. Donc on
prend les deux tokens, on assemble leurs orthographes et on demande à
la routine si c'est un pp-token ou non. C'est simple, stupide et
efficace. L'autre alternative serait de redemander un redécoupage en
suite de tokens -- c'est le procédé traditionnel, par exemple gcc
-traditional.
| En autres mots, est-ce que la solution proposée par Jean-Marc doit
| échouer si le nom du cible (TARGET) était PS-2, à la place de PS2 ?
Non, la solution proposée par Jean-Marc marche même si TARGET était
PS-2 à la place de PS2. La raison est qu'il n'utilise pas l'opérateur
## qui pose de problème dans le cas de INCFILE(2.2).
| (Et en passant, je crois que la version « correcte » de ce qu'il
| voulait faire serait :
| #define PATH_CONTROLLER_JOYPAD <controller##/##src##/##TARGET##/##Joypad.h>
Non, ce n'est pas correcte pour la même raison qu'avant : quand tu
concatènes {controller} et {/}, tu n'obtiens pas un pp-token valide.
writes:
| Gabriel Dos Reis wrote in message
| news:...
| > writes:
| En attendant : je trouve dommage que g++ ait décidé à casser du code qui
G++ n'a pas décidé de casser du code.
G++ a corrigé des bugs dans son implémentation. Si tu en trouves de
vrais bugs, mais vraiement de vrais, tu sais que je serais plus
qu'heureux que tu le rapportes.
Pour l'assistance, je rappelle que la forme de Jean-Marc est celle
basée directement sur les exemples de la norme.
kanze@gabi-soft.fr writes:
| Gabriel Dos Reis <gdr@cs.tamu.edu> wrote in message
| news:<m3pt7h478p.fsf@merlin.cs.tamu.edu>...
| > kanze@gabi-soft.fr writes:
| En attendant : je trouve dommage que g++ ait décidé à casser du code qui
G++ n'a pas décidé de casser du code.
G++ a corrigé des bugs dans son implémentation. Si tu en trouves de
vrais bugs, mais vraiement de vrais, tu sais que je serais plus
qu'heureux que tu le rapportes.
Pour l'assistance, je rappelle que la forme de Jean-Marc est celle
basée directement sur les exemples de la norme.
writes:
| Gabriel Dos Reis wrote in message
| news:...
| > writes:
| En attendant : je trouve dommage que g++ ait décidé à casser du code qui
G++ n'a pas décidé de casser du code.
G++ a corrigé des bugs dans son implémentation. Si tu en trouves de
vrais bugs, mais vraiement de vrais, tu sais que je serais plus
qu'heureux que tu le rapportes.
Pour l'assistance, je rappelle que la forme de Jean-Marc est celle
basée directement sur les exemples de la norme.