60

C'est surtout la syntaxe qui est un peu moisie..
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

61

Non le truc de RHJPP est sale, le fonctionnement de printf c'est FORMAT(obligatoire)+ARGS(eventuellement vide), pas ARGS(eventuellement vide)+""

Pas besoin de "truc" quand la methode officielle existe grin

62

En utilisant la bibliothèque P99 (flemme de devoir tout réécrire !) : #include "p99_if.h" #define CHECK(condition, label, ...) \ if (!(condition)) { \ fprintf (stderr, "%s, %s, %i\n", __FILE__, __func__, __LINE__); \ P99_IF_EMPTY(__VA_ARGS__) () (fprintf(stderr, __VA_ARGS__);) \ goto label; \ } CHECK(1, error); CHECK(1, error, "Data is %d\n", 2);

donne bien: if (!(1)) { fprintf (stderr, "%s, %s, %i\n", "test.c", __func__, 12); goto error; }; if (!(1)) { fprintf (stderr, "%s, %s, %i\n", "test.c", __func__, 14); fprintf(stderr, "Data is %d\n", 2); goto error; };

Elle est dispo là: http://p99.gforge.inria.fr/

(pour info, c'est 100% standard compliant).

63

squalyl (./61) :
Non le truc de RHJPP est sale, le fonctionnement de printf c'est FORMAT(obligatoire)+ARGS(eventuellement vide), pas ARGS(eventuellement vide)+""

Pas besoin de "truc" quand la methode officielle existe grin.gif?14

Ok, mais c'est précisément à la macro que je confie la merde.
Ce qui m'intéresse, c'est de pouvoir faire des appels avec ou sans chaine de caractère. Et en l'occurence, le truc de RHJPP donne un format vide et pas d'argument derrière, où est le problème ? Je dois simplement passer -Wno-format-zero-length parce que printf prévient si on passe une chaine vide.

PpHd -> Merci, je regarde, ça a l'air chouette cette lib. smile

64

pour moi le fait de devoir ajouter un -Wkekchoz n'est pas satisfaisant smile

Apres chacun fait comme il veut smile

65

Bon, j'avoue ma mauvaise foi, "ça me va" parce que "j'ai rien d'autre" grin
En fait, le warning ici est fait non pour signaler une construction dangereuse genre if (a = b), mais amha pour signaler une erreur d'innatention ("attention mec, t'as rien dans ta string, ya pas un souci ?"). Donc on est pas du tout dans le même degré de craditude. embarrassed

66

squalyl (./64) :
pour moi le fait de devoir ajouter un -Wkekchoz n'est pas satisfaisant smile

Apres chacun fait comme il veut smile


Si, chaque compilateur devrait etre en -Wall -Werror par defaut embarrassed
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

67

Mais ça ne suffit pas embarrassed
Comme l'indique bien son nom, -Wall n'active pas tous les warnings. -Wextra non plus, d'ailleurs sad
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

68

C'est vrai, mais c'est mieux que le comportement par defaut embarrassed
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

69

Si tu ne veux pas de warning, suffit que la chaine ne soit pas vide ^^#define CHECK(condition, label, ...) \ if (!(condition)) { \ fprintf(stderr, "%s, %s, %i\n", __FILE__, __func__, __LINE__); \ if (*#__VA_ARGS__) \ fprintf(stderr, ##__VA_ARGS__, "pas vide"); \ goto label; \ }

C'est sûr que ce n'est pas parfaitement propre et il y a un risque de non-détection du manque d'un argument chaine de caractère. S'il y a un %s en trop dans le format, ça ne sera pas détecté et ça affichera pas vide...
À voir si c'est acceptable pour Folco. J'ai donné cette solution parce qu'elle fonctionne et est rapide à mettre en place (surtout à 3 heures cheeky).
avatar

70

Non, ça ne va pas, "pas vide" sera affiché à chaque fois que j'appelle la macro sans chaine de caractère, non ? du coup ça ferait super crade ^^

Et j'ai écrit ça, c'est plus explicite, et c'est plus lisible en fonction des cas :#define IF_TRUE(condition, label, ...) \ if (condition) { \ fprintf (stderr, ##__VA_ARGS__, ""); \ fprintf (stderr, "%s, %s, %i\n", __FILE__, __func__, __LINE__); \ goto label; \ } #define IF_FALSE(condition, label, ...) IF_TRUE (!(condition), label, ##__VA_ARGS__)

71

Folco (./70) :
Non, ça ne va pas, "pas vide" sera affiché à chaque fois que j'appelle la macro sans chaine de caractère, non ? du coup ça ferait super crade ^^
Non, il y a if (*#__VA_ARGS__) pour gérer ce cas wink
avatar

72

Ah yep, j'ai lu trop vite, bien vu merci. smile
flanker (./67) :
Mais ça ne suffit pas embarrassed
Comme l'indique bien son nom, -Wall n'active pas tous les warnings. -Wextra non plus, d'ailleurs sad

Tiens, je découvre que -Wextra n'est autre que -W, si je comprends bien la doc, mais que -W serait deprecated : https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

73

74

Bon, donc au final, j'ai ces macros :#define IF_TRUE(condition, label, ...) \ if (condition) { \ if (*#__VA_ARGS__) { \ fprintf (stderr, ##__VA_ARGS__, ""); \ fprintf (stderr, "\n"); \ } \ fprintf (stderr, "%s, %s, %i\n", __FILE__, __func__, __LINE__); \ goto label; \ } #define IF_FALSE(condition, label, ...) IF_TRUE (!(condition), label, ##__VA_ARGS__)
Et ça donne des choses de ce genre :int main (void) { // Initialization int ret = EXIT_FAILURE; IF_FALSE (InitSdl (), SdlFail) IF_FALSE (InitFont (), FontFail) IF_FALSE (InitRessources(), RessourcesFail) IF_FALSE (InitGameState(), GameStateFail) // Game engine IF_FALSE (GameStateEngine(), EngineFail) ret = EXIT_SUCCESS; // Cleanup EngineFail: DeinitGameState (); GameStateFail: DeinitRessources (); RessourcesFail: DeinitFont (); FontFail: DeinitSdl (); SdlFail: return ret; }
Le IF_FALSE/TRUE est limite trop explicite, mais c'est bien plus simple à lire que IF/IFN (pour moi).

75

, label, ##__VA_ARGS__)Bon, vala maintenant : #define IF_TRUE(condition, label, ...) \ if (condition) { \ if (*#__VA_ARGS__) { \ fprintf (stderr, "ERROR: "); \ fprintf (stderr, ##__VA_ARGS__, ""); \ fprintf (stderr, "\n"); \ } \ fprintf (stderr, "TRACE: %s:%i, in %s()\n", __FILE__, __LINE__, __func__); \ goto label; \ } #define IF_FALSE(condition, label, ...) IF_TRUE (!(condition)
Ca donne des trucs comme ça :
folco@Foch:~/fpgc/Debug$ ./fpgc
ERROR: Couldn't open ../spr/ButtonExit_out.png
TRACE: /home/folco/fpgc/src/Ressources.c:18, in LoadSpriteFile()
TRACE: /home/folco/fpgc/src/Ressources.c:32, in InitRessources()
TRACE: /home/folco/fpgc/src/main.c:15, in main()
folco@Foch:~/fpgc/Debug$ 

Par contre, je dois passer -Wno-format-extra-args pour éviter un warning, dans le cas où je fournis une chaine avec des donénes à formatter, genre IF_TRUE (m_count == GS_COUNT_MAX, Exit, "ERROR: max game state reached, %i", GS_COUNT_MAX), parce qu'il n'y a que %i à formater, et gcc voit GS_COUNT_MAX et le "" de la macro. J'ai pas trouvé comment éviter ça (sans utiliser une lib telle celle proposée par PpHd).

76

top
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

77

C'est vraiment génial ce truc, merci beaucoup pour votre aide, parce que à l'instant, j'ai eu ça :
$ ./fpgc 
TRACE: /home/folco/fpgc/src/GameStates.c:130, in GameStateEngine()
TRACE: /home/folco/fpgc/src/main.c:19, in main()

Et en fait, ya pas d'erreur, juste une faute de logique à cette ligne, qui fait que ça quitte alors que ça devrait pas. Sans vérification des retours, je sais pas comment j'aurais fait pour trouver, j'aurais du tracer et je me serais bien fait chier grin
En tout cas, maintenant, ça donne du code de ce genre, et c'est bien plus simple à lire, et certainement plus facile à déboguer. smile

78

Bug report et patch embarrassed :
-// This function does nothing else returning true, and allows a game state to ignore some callbacks
+// This function does nothing besides returning true, and allows a game state to ignore some callbacks
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

79

MERCI !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Par contre, c'est un patch unifié ou pas ? Je sais pas trop comment le déployer, je vais en parler avec les responsables de mes équipes de dev lundi matin. embarrassed

80

hehe
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

81

Si tu veux ameliorer ta macro, tu peux utiliser backtrace() pour savoir exactement l'ordre d'appel pour savoir comment tu en es arrive la smile

http://man7.org/linux/man-pages/man3/backtrace.3.html

Tu dois meme pouvoir mettre une fonction qui joue le role de breakpoint pour un debugger smile
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

82

C'est chouette cette fonction, merci beaucoup ! grin

(eh oui, quand on code pas bien, on apprend tous les moyens pour déboguer, c'est comme ça grin)

83

Par contre attention backtrace est moyennement portable, il y a des plateforme ou il ne fait rien.. :/
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

84

Folco (./75) :
J'ai pas trouvé comment éviter ça (sans utiliser une lib telle celle proposée par PpHd).


C'est juste des .h, rien d'autres. Tu peux récupérer juste ce que tu veux.

85

Folco (./75) :
Par contre, je dois passer -Wno-format-extra-args pour éviter un warning, dans le cas où je fournis une chaine avec des donénes à formatter, genre IF_TRUE (m_count == GS_COUNT_MAX, Exit, "ERROR: max game state reached, %i", GS_COUNT_MAX), parce qu'il n'y a que %i à formater, et gcc voit GS_COUNT_MAX et le "" de la macro. J'ai pas trouvé comment éviter ça (sans utiliser une lib telle celle proposée par PpHd).

Pourquoi ne pas continuer avec le bricolage ? grin#define SP_FPRINTF(file, format, ...) \ if (*#__VA_ARGS__) { \ const char *f = format; \ size_t l = strlen(f); \ char f2[l + 3]; \ strcpy (f2, f); \ strcpy (f2 + l, "%s"); \ fprintf (file, f2, ##__VA_ARGS__); \ } else { \ fprintf (file, format); \ } #define IF_TRUE(condition, label, ...) \ if (condition) { \ if (*#__VA_ARGS__) { \ fprintf (stderr, "ERROR: "); \ SP_FPRINTF (stderr, ##__VA_ARGS__, "\n"); \ } \ fprintf (stderr, "TRACE: %s:%i, in %s()\n", __FILE__, __LINE__, __func__); \ goto label; \ } #define IF_FALSE(condition, label, ...) IF_TRUE (!(condition), label, ##__VA_ARGS__)

J'ai fait une marco, mais tu peux faire pareil en fonctionnel wink
avatar

86

PpHd (./84) :
C'est juste des .h, rien d'autres. Tu peux récupérer juste ce que tu veux.

J'ai meme essayé de les comprendre, c'est certainement très puissant, mais les sources sont quand même vachement capillo-tractées, et j'ai pas compris comment ça marchait, donc j'utilise pas. On a ses principes, non mais. embarrassed

Merci RHJPP, je continuerai à explorer quand j'aurai résoudru des trucs plus merdiques à coté grin

87

Folco (./86) :
J'ai meme essayé de les comprendre, c'est certainement très puissant, mais les sources sont quand même vachement capillo-tractées, et j'ai pas compris comment ça marchait, donc j'utilise pas. On a ses principes, non mais. embarrassed.gif?14


Ah mais la méta programmation en préprocesseur C n'est pas compliqué. C'est juste des couches, empilées dans des couches, empilées dans des couches, pour faire les substitutions que l'on veut.
Tout repose sur P99_HAS_COMMA qui retourne 0 ou 1 si l'argument qu'on lui donne en paramètre à une virgule.
Pour ce faire, on définit la macro comme étant: #define P99_HAS_COMMA(...) P00_ARG(__VA_ARGS__, \ 1, 1, 1, 1, 1, 1, 1, \ ... 1, 1, 1, 1, 1, 1, 1, 1, \ 1, 1, 1, 1, 1, 1, 0, 0)
P00_ARG retourne son 159ième argument.
ie. on utilise l'argument VA_ARGS qui va décaler ou pas les arguments donnés en paramètre à P00_ARG qui va retourner 1 ou 0 selon que l'on a une virgule ou pas.

Avec cette macro, on peut construire P99_IS_EMPTY: #define P99_IS_EMPTY(...) \ P00_ISEMPTY( \ /* test if there is just one argument, that might be empty */ \ P99_HAS_COMMA(__VA_ARGS__), \ /* test if P99_IS__EQ__ together with the argument \ adds a comma */ \ P99_HAS_COMMA(P00_IS__EQ__ __VA_ARGS__), \ /* test if the argument together with a parenthesis \ adds a comma */ \ P99_HAS_COMMA(__VA_ARGS__ (/*empty*/)), \ /* test if placing it between P99_IS__EQ__ and the \ parenthesis adds a comma */ \ P99_HAS_COMMA(P00_IS__EQ__ __VA_ARGS__ (/*empty*/)) \ )
Le point clé est le dernier argument : si __VA_ARGS__ est vide, on obtient : P00_IS__EQ__ (/*empty*/), qui reconnu comme un appel de macro, qui va injecter une virgule !
Donc l'argument est vide lorsque seul le dernier élément (P99_HAS_COMMA(P00_IS__EQ__ __VA_ARGS__ (/*empty*/)) ) est vrai et pas les autres !
Donc on évalue tous les arguments, qui ne valent que 1 ou 0. On concatène le tout (P00_ISEMPTY) et via une autre rangé de macro, on dit si oui ou non on a gagné: #define P00_IS_EMPTY_CASE_0000 P00_IS_EMPTY_CASE_0000 #define P00_IS_EMPTY_CASE_0001 , #define P00_IS_EMPTY_CASE_0010 P00_IS_EMPTY_CASE_0010 #define P00_IS_EMPTY_CASE_0011 P00_IS_EMPTY_CASE_0011 ....
Là, il réutilise sa macro IS_COMMA pour dire si oui ou non, c'est vide. J'aime beaucoup love

A partir de là tu as 0 ou 1 selon que c'est vide ou pas.
Tu redéfinis des macros #define MACHIN_TO_KEEP_IF_1(...) #define MACHIN_TO_KEEP_IF_0(...) __VA_ARGS__
tu concatènes ta sortie de ta macro précédente avec MACHIN_TO_KEEP (avec le bon niveau de substitution) et si c'est pas vide, tu expanses ton argument.
En faisant simple, ca donne
#define KEEP_IF_NOT_EMPTY(...) MACHIN_TO_KEEP_ ## IS_EMPTY(__VA_ARGS__) (func(__VA_ARGS__))
(sauf que ca ne va pas marcher parque les substitutions ne se passeront pas au bon moment (## est prioritaire sur l'appel d'une macro !) Mais le principe est là.

88

Merci beaucoup pour l'explication en détail. En fait, à la base, j'ai regardé comment ça marchait car je pensais trouver une méthode rigoureuse, je veux dire générique. Là, ça s'appuie sur un tableau contenant un nombre fixé d'éléments, tout comme font certaines autres macros qui comptent les arguments d'une __VA_ARGS__. C'est très bien trouvé, c'est ingénieux, mais je cherchais quelque chose de conçu pour faire ça dans le langage du préproc. Apparemment, ça n'existe pas.
PpHd (./87) :
avec le bon niveau de substitution

Alors voilà, j'en suis à essayer d'écrire des tucs qui marchent avec deux niveaux de substitution, et qui présentent un minimum d'intér^et pour mon besoin, c'est à dire autre chose que les exemples bateau de mon bouquin. On y va pas à pas, mais c'est sympa comme gymnastique d'esprit. grin

Merci encore pour tout happy