OVH Cloud OVH Cloud

include avec define ?

34 réponses
Avatar
Amerio
Bonjour,

J'ai un code dont l'interface est commune a toutes mes plateformes, mais
dont l'implémentation est fortement spécifique.
Ex : controller/Joypad.h et controller/src/PS2/Joypad.h et
controller/src/XBOX/Joypad.h
(oui ce sont des .h, inline oblige)

Dans le code source (controller/src/Joypad.cpp), on doit inclure le bon
src/???/Joypad.h
Actuellement, on fait cela, sans pb (target défini a PS2 ou XBOX, etc..):
#define PATH_CONTROLLER_JOYPAD <controller/src/##TARGET##/Joypad.h>
#include PATH_CONTROLLER_JOYPAD

Mais cette technique ne marche plus avec le dernier (?) gcc (au passage :
impossible de changer de version de gcc, cette version est imposée : 3.3.3
custom). Il nous jete avec le msg :
pasting "/" and "TARGET" does not give a valid preprocessing token

Ma question : cette facon de faire (define puis include) me semblait la plus
simple. Mais est elle standard ? Y-a-t-il un autre moyen ? (sans faire 36
#if (TARGET==XXX) etc)

10 réponses

1 2 3 4
Avatar
Jean-Marc Bourguet
writes:

Jean-Marc Bourguet wrote in message
news:...
"Amerio" writes:

#define PATH_CONTROLLER_JOYPAD <controller/src/##TARGET##/Joypad.h>
#include PATH_CONTROLLER_JOYPAD


#define TARGET PS2
#define XSTR(x) #x
#define STR(x) XSTR(x)
#define PLATFILE(base,file) STR(base/TARGET/file)

#include PLATFILE(controller/src,Joypad.h)


Techniquement, c'est illégale selon la norme.


16.3.5/6 (qui est au milieu d'une note -- donc non normatif --
commencant a la page precedante et se terminant a la page suivante)
donne a peu pres la meme chose en exemple.

J'ai pas le temps d'aller faire de l'exegese pour me faire une opinion
personnelle.

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
James Kanze
Gabriel Dos Reis writes:

|> writes:

|> | Jean-Marc Bourguet wrote in message
|> | news:...
|> | > "Amerio" writes:

|> | > > #define PATH_CONTROLLER_JOYPAD <controller/src/##TARGET##/Joypad.h>
|> | > > #include PATH_CONTROLLER_JOYPAD

|> | > #define TARGET PS2
|> | > #define XSTR(x) #x
|> | > #define STR(x) XSTR(x)
|> | > #define PLATFILE(base,file) STR(base/TARGET/file)

|> | > #include PLATFILE(controller/src,Joypad.h)

|> | Techniquement, c'est illégale selon la norme. (Mais je doute que
|> | tu trouves une implémentation où il ne marche pas.) Le problème,
|> | c'est que l'opérateur # renvoie un seul token, du type « string
|> | literal ». Or, un « string literal » n'est pas un token légal ici
|> | -- il faut trois tokens, un « " » (qui n'est un token que dans ce
|> | contexte-ci), un « q-char-sequence », et un « " ».

|> Visiblement, ton interprétation est en conflit avec celle des gens
|> qui ont écrit cette partie de la norme C et C++.

Enfin, ce n'était pas mon interprétation, au moins au départ. C'était à
peu près le consensus qui en est sortie d'une discussion dans
comp.std.c, il y a plus de dix ans. Dont certains auteurs de la norme C
ont fait partie.

En attendant, évidemment, c'est bien ce que dit la norme. Tu n'as qu'à
la lire.

--
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
Gabriel Dos Reis writes:

|> writes:

|> [...]

|> | Dans la pratique, étant donné le fait que ce que c'est qu'un token
|> | dépend du contexte, à peu près la seule solution qui tient la
|> | route pour une implémentation, c'est de traiter faire toute
|> | l'expansion des macros comme texte, et puis tokeniser le résultat
|> | (en contexte). Sa solution original est légal

|> Citations de la norme, please ?

La norme ne dit pas comment faire l'implémentation. Et ça aidera si tu
lisais ce qu'on écrit un peu -- je n'exclus pas la possibilité d'une
autre solution. Mais je ne le vois pas.

|> | -- g++ le réfuse parce qu'ils ont fait l'erreur d'essayer à
|> | tokeniser dans l'expansion des macros, et sans le contexte
|> | d'utilisation.

|> Chapitres et versets, please ?

Chapitres et versets de quoi ? La norme dit qu'il faut que le résultat
de ## soit un token. Mais ce que c'est qu'un token dépend du contexte.
(Chose que la norme dit explicitement dans §2.1/3.) Dans le contexte où
l'expansion du macro a lieu, on est dans un h-char-sequence. Est-ce que
tu prétends que « /xxx » n'est pas une h-char-sequence légal ?

|> | Qu'il invoque son macro n'importe où que dans une include, leur
|> | message d'erreur serait correct. Mais non réquis, puisque c'est un
|> | comportement indéfini. Essayer de donner un message en cas de
|> | comportement indéfini, c'est bien. Mais si les versions antérieur
|> | du compilateur l'ont permis, avec un comportement « défini », le
|> | moindre respect de l'utilisateur exige que le message ne soit
|> | qu'un avertissement. Et aussi, évidemment,

|> Je suggère que tu envoies un message à pour leur
|> demander de permettre tous les bugs qui « avaient un comportement
|> "défini" », pour le mondre respect de l'utilisateur.

Je suggère que tu apprends que le monde existait bien avant que tu t'es
mis à faire du C++, et que la technique que g++ rejette est une
technique connue et répandue, parce qu'il y a plus de dix ans, dans les
discussions avec les auteurs de la norme C, la conclusion était que
c'était la seule solution légale.

--
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
Gabriel Dos Reis writes:

|> "Amerio" writes:

|> | J'ai un code dont l'interface est commune a toutes mes plateformes, mais
|> | dont l'implémentation est fortement spécifique.
|> | Ex : controller/Joypad.h et controller/src/PS2/Joypad.h et
|> | controller/src/XBOX/Joypad.h
|> | (oui ce sont des .h, inline oblige)

|> | Dans le code source (controller/src/Joypad.cpp), on doit inclure le bon
|> | src/???/Joypad.h
|> | Actuellement, on fait cela, sans pb (target défini a PS2 ou XBOX, etc..):
|> | #define PATH_CONTROLLER_JOYPAD <controller/src/##TARGET##/Joypad.h>
|> | #include PATH_CONTROLLER_JOYPAD

|> | Mais cette technique ne marche plus avec le dernier (?) gcc (au
|> | passage : impossible de changer de version de gcc, cette version
|> | est imposée : 3.3.3 custom). Il nous jete avec le msg :
|> | pasting "/" and "TARGET" does not give a valid preprocessing token

|> C'est que tu dois « stringifier » "/" avant de le concatener avec
|> TARGET. En fait, tu dois « stringifier » toute la ligne, où ne
|> concatener que des opérandes « stringifiées ».

Formellement, dans ce contexte-ci, la stringification n'est pas légale,
au moins selon la norme. Évidemment, je ne connais pas de compilateur
où il ne fonctionne pas. Mais avant g++ 3.4, je ne connaissais pas de
compilateur où sa technique ne marchait pas non plus, surtout parce qu'à
l'encontre de la stringification, c'est légale.

--
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
Gabriel Dos Reis
James Kanze writes:

| Gabriel Dos Reis writes:
|
| |> writes:
|
| |> | Jean-Marc Bourguet wrote in message
| |> | news:...
| |> | > "Amerio" writes:
|
| |> | > > #define PATH_CONTROLLER_JOYPAD <controller/src/##TARGET##/Joypad.h>
| |> | > > #include PATH_CONTROLLER_JOYPAD
|
| |> | > #define TARGET PS2
| |> | > #define XSTR(x) #x
| |> | > #define STR(x) XSTR(x)
| |> | > #define PLATFILE(base,file) STR(base/TARGET/file)
|
| |> | > #include PLATFILE(controller/src,Joypad.h)
|
| |> | Techniquement, c'est illégale selon la norme. (Mais je doute que
| |> | tu trouves une implémentation où il ne marche pas.) Le problème,
| |> | c'est que l'opérateur # renvoie un seul token, du type « string
| |> | literal ». Or, un « string literal » n'est pas un token légal ici
| |> | -- il faut trois tokens, un « " » (qui n'est un token que dans ce
| |> | contexte-ci), un « q-char-sequence », et un « " ».
|
| |> Visiblement, ton interprétation est en conflit avec celle des gens
| |> qui ont écrit cette partie de la norme C et C++.
|
| Enfin, ce n'était pas mon interprétation, au moins au départ. C'était à
| peu près le consensus qui en est sortie d'une discussion dans
| comp.std.c, il y a plus de dix ans. Dont certains auteurs de la norme C
| ont fait partie.

Donc dix ans après, ces supposés auteurs ont revu la norme C -- et ont
produit C99. Le comité C a revisé le proprocesseur sans rien touché à la
partie en question. Mieux, il l'a documnté pour expliquer ce qui se
passe.

[#6] EXAMPLE 4 To illustrate the rules for creating
character string literals and concatenating tokens, the
sequence

#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
#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("abcd", "abc", '4') // this goes away
== 0) str(: @n), s);
#include xstr(INCFILE(2).h)
glue(HIGH, LOW);
xglue(HIGH, LOW)

results in

printf("x" "1" "= %d, x" "2" "= %s", x1, x2);
fputs(
"strncmp("abcd", "abc", '4') == 0" ": @n",
s);
#include "vers2.h" (after macro replacement, before file acces
s)
"hello";
"hello" ", world"

or, after concatenation of the character string literals,

printf("x1= %d, x2= %s", x1, x2);
fputs(
"strncmp("abcd", "abc", '4') == 0: @n",
s);
#include "vers2.h" (after macro replacement, before file acces
s)
"hello";
"hello, world"

Space around the # and ## tokens in the macro definition is
optional.


Je crois que tes experts t'ont floué ;-)

-- Gaby
Avatar
Gabriel Dos Reis
James Kanze writes:

| Gabriel Dos Reis writes:
|
| |> writes:
|
| |> [...]
|
| |> | Dans la pratique, étant donné le fait que ce que c'est qu'un token
| |> | dépend du contexte, à peu près la seule solution qui tient la
| |> | route pour une implémentation, c'est de traiter faire toute
| |> | l'expansion des macros comme texte, et puis tokeniser le résultat
| |> | (en contexte). Sa solution original est légal
|
| |> Citations de la norme, please ?
|
| La norme ne dit pas comment faire l'implémentation.

Ben voyons.

Je crois que tu n'es pas crédible sur ce coup. Voir mon autre message
ou la norme C (n'a pas changé les règles sur ce point) mais explique
ce qui se passe -- pour ceux qui n'auraient pas compris ce qu'est un
pp-token et ce qu'est une chaîne de caractères.

| Et ça aidera si tu lisais ce qu'on écrit un peu

J'ai lu ce que tu as écris et j'ai été assez poli pour ne pas dire que
tu mentais. Alors j'ai demandé chapitres et versets sur lesquels tu
t'appuies pour dire que ce qu'il a écrit est légal. Incapable de
trouver de telles justifications, tu reviens me dire que la norme ne
décrit pas comment une implémentation est faite. Mais ce n'est pas la
question que je t'ai posée. Tu affirmes que quelque chose est légal,
tu dois pourvoir le justifier en citant les paragraphes de la norme
qui permettent de l'inférer indépendamment de toute implémentation.

| -- je n'exclus pas la possibilité d'une
| autre solution. Mais je ne le vois pas.
|
| |> | -- g++ le réfuse parce qu'ils ont fait l'erreur d'essayer à
| |> | tokeniser dans l'expansion des macros, et sans le contexte
| |> | d'utilisation.
|
| |> Chapitres et versets, please ?
|
| Chapitres et versets de quoi ? La norme dit qu'il faut que le résultat
| de ## soit un token. Mais ce que c'est qu'un token dépend du contexte.
| (Chose que la norme dit explicitement dans §2.1/3.) Dans le contexte où

Est-ce qu'il t'es venu à l'esprit de lire ce qu'est une chaîne de
caratères et comment marche une expansion de macro ?

[...]

| Je suggère que tu apprends que le monde existait bien avant que tu t'es

Je te retourne le conseil et te suggère fortement de te pencher sur la
notion de chaînes de caractères et d'expansion de macros en C. Cela nous
évitera de nous perdre dans des mensonges que cela que tu as produit
et que tu ne peux justifier.

-- Gaby
Avatar
Gabriel Dos Reis
James Kanze writes:

| Gabriel Dos Reis writes:
|
| |> "Amerio" writes:
|
| |> | J'ai un code dont l'interface est commune a toutes mes plateformes, mais
| |> | dont l'implémentation est fortement spécifique.
| |> | Ex : controller/Joypad.h et controller/src/PS2/Joypad.h et
| |> | controller/src/XBOX/Joypad.h
| |> | (oui ce sont des .h, inline oblige)
|
| |> | Dans le code source (controller/src/Joypad.cpp), on doit inclure le bon
| |> | src/???/Joypad.h
| |> | Actuellement, on fait cela, sans pb (target défini a PS2 ou XBOX, etc..):
| |> | #define PATH_CONTROLLER_JOYPAD <controller/src/##TARGET##/Joypad.h>
| |> | #include PATH_CONTROLLER_JOYPAD
|
| |> | Mais cette technique ne marche plus avec le dernier (?) gcc (au
| |> | passage : impossible de changer de version de gcc, cette version
| |> | est imposée : 3.3.3 custom). Il nous jete avec le msg :
| |> | pasting "/" and "TARGET" does not give a valid preprocessing token
|
| |> C'est que tu dois « stringifier » "/" avant de le concatener avec
| |> TARGET. En fait, tu dois « stringifier » toute la ligne, où ne
| |> concatener que des opérandes « stringifiées ».
|
| Formellement, dans ce contexte-ci, la stringification n'est pas légale,

pour quelles raisons ?

| au moins selon la norme.

Chapitres et versets ?

| Évidemment, je ne connais pas de compilateur
| où il ne fonctionne pas.

Est-ce qu'il t'es venu à l'esprit que cela marche aussi parce que
c'est ce que demande la norme ?

-- Gaby
Avatar
Gabriel Dos Reis
"Michel Michaud" writes:

| Comme personne ne le mentionne... Est-ce que c'est normal que tous
| tes messages semblent paraître avec un décalage d'une journée ?

Non, c'est pas normal. Je vais avoir uen conversation avec la machine.

Merci.

-- Gaby
Avatar
Gabriel Dos Reis
James Kanze writes:

| Gabriel Dos Reis writes:
|
| |> James Kanze writes:
|
| |> | Gabriel Dos Reis writes:
|
| |> | |> "Amerio" writes:
|
| |> | |> | J'ai un code dont l'interface est commune a toutes mes
| |> | |> | plateformes, mais dont l'implémentation est fortement
| |> | |> | spécifique. Ex : controller/Joypad.h et
| |> | |> | controller/src/PS2/Joypad.h et controller/src/XBOX/Joypad.h
| |> | |> | (oui ce sont des .h, inline oblige)
|
| |> | |> | Dans le code source (controller/src/Joypad.cpp), on doit
| |> | |> | inclure le bon src/???/Joypad.h Actuellement, on fait cela,
| |> | |> | sans pb (target défini a PS2 ou XBOX, etc..):
| |> | |> | #define PATH_CONTROLLER_JOYPAD <controller/src/##TARGET##/Joypad.h>
| |> | |> | #include PATH_CONTROLLER_JOYPAD
|
| |> | |> | Mais cette technique ne marche plus avec le dernier (?) gcc
| |> | |> | (au passage : impossible de changer de version de gcc, cette
| |> | |> | version est imposée : 3.3.3 custom). Il nous jete avec le
| |> | |> | msg : pasting "/" and "TARGET" does not give a valid
| |> | |> | preprocessing token
|
| |> | |> C'est que tu dois « stringifier » "/" avant de le concatener
| |> | |> avec TARGET. En fait, tu dois « stringifier » toute la ligne,
| |> | |> où ne concatener que des opérandes « stringifiées ».
|
| |> | Formellement, dans ce contexte-ci, la stringification n'est pas légale,
|
| |> pour quelles raisons ?
|
| Parce que la stringification donne toujours une constante de chaîne de
| caractêres (« string literal »),

oui et tu sais ce que c'est ?

| et une constante de chaîne de
| caractères n'est pas légale dans ce contexte.

Groumph, lis un peu le texte pour savoir ce qu'est une chaîne de
caractères et ce que fait l'opérateur # !

| |> | au moins selon la norme.
|
| |> Chapitres et versets ?
|
| §16.2 et §16.3.2. C'est on ne peut plus clair, pour ceux qui savent
| lire.

Donc, je suppose que tu sais lire, puisque cela te paraît clair.
Cependant, il me paraît évident que la fonction qui permet de
comprendre ce que tu lis n'a pas été activée pendant ta studieuse
lecture. Je te suggère donc de l'activer et de lire :

If, in the replacement list, a parameter is immediately preceded by
a # preprocessing token, both are replaced by a single character
string literal preprocessing token that contains the spelling of the
preprocessing token sequence for the corresponding argument. Each
occurrence of white space between the argument s preprocessing
tokens becomes a single space character in the character string
literal. White space before the first preprocessing token and after
the last preprocessing token comprising the argument is
deleted. Otherwise, the original spelling of each preprocessing
token in the argument is retained in the character string literal,
except for special handling for producing the spelling of string
literals and character literals: a character is inserted before
each " and character of a character literal or string literal
(including the delimiting " characters). If the replacement that
results is not a valid character string literal, the behavior is
undefined. The order of evaluation of # and ## operators is
unspecified.

2.13.4

string-literal:
"s-char-sequence_opt"
L"s-char-sequence_opt"

s-char-sequence:
s-char
s-char-sequence s-char

s-char:
any member of the source character set except
the double quote ", backslash , or new-line character
escape-sequence
universal-character-name


| |> | Évidemment, je ne connais pas de compilateur où il ne fonctionne
| |> | pas.
|
| |> Est-ce qu'il t'es venu à l'esprit que cela marche aussi parce que
| |> c'est ce que demande la norme ?
|
| Vue que ce n'est pas ce que démande la norme.

Uniquement dans ton imagination. Si tu savais vraiment lire comme tu
le prétends, tu aurais vu l'exemple que donne la norme pour illustrer
pour des gens qui n'auraient pas compris. Mais je présume, c'est plus
facile d'invoquer des discussions fantomatiques qui auraient eu lieu
il y a dix ans aboutissant des mensonges que rien dans la norme ne
vient étayer que d'exercer le sens de la raison.

-- Gaby
Avatar
Michel Michaud
Comme personne ne le mentionne... Est-ce que c'est normal que tous
tes messages semblent paraître avec un décalage d'une journée ?

Suis-je le seul à voir ça ?

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/
1 2 3 4