Contrôle de type sur les macros - C - Programmation
Marsh Posté le 23-03-2007 à 14:01:34
lafourchette a écrit : Je peux lire dans beaucoup de documentations que les macros sont dangereuses parce qu'il n'y a aucun contrôle de type effectué dessus. Je ne comprends pas pourquoi |
Ca pose problème dans les pseudo fonctions avec paramètres. Les paramètres des macros ne sont pas typés et font simplement un remplacement de texte.
Code :
|
Avec la macro : pas de warning
Avec la fonction : warning
Marsh Posté le 24-03-2007 à 13:15:02
Ainsi présenté, c'est déjà plus lumineux.
Dans le cas 0, le cas de la fonction, j'ai effectivement un warning:
[Warning] passing arg 2 of `str_to_double' from incompatible pointer type
Le compilateur à, je suppose, constaté qu'à l'appel de la fonction "str_to_double", les paramètres effectifs divergeaient par rapport aux paramètres formels.
Mais je peux executer le programme et j'obtiens:
1889785610 Résultat sans doute sans signification intinsèque mais qui doit pouvoir s'expliquer.
Dans le cas 1, le cas de la macro, tout se passe bien et j'obtiens:
1234 Résultat que cette fois ci je peux expliquer.
Par contre, dans les deux cas j'ai commis à la lecture du code, une erreur de débutant et j'espère que je suis pas le seul:
J'étais persuadé que le compilateur m'enverrait un petit avertissement de principe pour essayer d'affecter le contenu d'une variable de type double à une variable de type int.
Marsh Posté le 24-03-2007 à 19:16:02
lafourchette a écrit : J'étais persuadé que le compilateur m'enverrait un petit avertissement de principe pour essayer d'affecter le contenu d'une variable de type double à une variable de type int. |
Où vois-tu une affectation de double vers int ? strtod() renvoie un double, "p" étant de type "double étoile" il s'ensuit que "*p" est de type "double" donc en affectant "strtod()" à "*p" tout est correct...
lafourchette a écrit : Mais je peux executer le programme et j'obtiens: |
De façon très facile: la fonction "strtod" à laquelle tu passes un pointeur (une adresse) ira stocker à cette adresse les 8 octets correspondant à une valeur au format "double" qu'elle calcule, valeur codée sur 8 octets (selon les spécifications du codage des double avec la mantisse, l'exposant, etc...).
Toi, tu lui passes l'adresse d'un "int" qui est convertie en adresse de double par le cast implicite. Une adresse étant toujours une adresse et étant considérée comme pointant sur 8 octets au format "double", la fonction va donc stocker à cette adresse les 8 octets du double (ici risque de plantage car il est possible que les 4 octets suivants le "int" ne soient pas disponibles mais passons).
Au retour de la fonction, quand tu affiches ton "int", ça récupère les 4 premiers octets de la zone mémoire correspondante, les décode selon les spécifications du codage des "int" (1 bit de signe, 31 bits de valeur) et t'affiche le résultat.
Donc t'as codé en spécification "double" et tu décodes en spécifications "int". Déjà que les spécifications ne sont pas les mêmes et en plus tu n'en décodes que la moitié de ce qui a été mis. C'aurait été miraculeux que tu obtiennes "1234"...
Marsh Posté le 26-03-2007 à 15:37:41
Sve@r a écrit : |
Citation : Où vois-tu une affectation de double vers int ? strtod() renvoie un double, "p" étant de type "double étoile" il s'ensuit que "*p" est de type "double" donc en affectant "strtod()" à "*p" tout est correct... |
C'est dans le cas de la macro en fait que j'ai un probleme.
Si je fais l'expansion de la macro à son appel j'obtiens
*(&x) = strtod("1234.56", NULL); soit
x = strtod("1234.56", NULL); x étant bien une variable de type int, non
Sur deux compilateurs différents, j'ai essayé d'affecter une constante décimale à un int.
Seul le second m'a mis un petit warning
Marsh Posté le 26-03-2007 à 21:08:42
lafourchette a écrit : |
Mouais. Tu peux essayer d'écrire "int x=2.5" voir si ton compilo te mettra un warning. En général, cela tombe dans le cadre du cast implicite...
Marsh Posté le 27-03-2007 à 12:56:50
Tu peux contrôler les types en faisant des affectations dans ta macro :
Code :
|
Marsh Posté le 27-03-2007 à 14:43:01
matafan a écrit : Tu peux contrôler les types en faisant des affectations dans ta macro :
|
Pourquoi faire une boucle qui ne bouclera pas ???
Code :
|
Marsh Posté le 27-03-2007 à 14:44:55
Sve@r a écrit : Pourquoi faire une boucle qui ne bouclera pas ???
|
Pour forcer l'usage du ';' en fin de macro. C'est une vielle ficelle de métier, je suis étonné que tu ne la connaisses pas...
Marsh Posté le 27-03-2007 à 14:50:21
Emmanuel Delahaye a écrit : Pour forcer l'usage du ';' en fin de macro. C'est une vielle ficelle de métier, je suis étonné que tu ne la connaisses pas... |
Joli. En plus, je m'étais même dit "tiens il a oublié le ';' après son while mais je ne vais pas lui faire remarquer un truc qui n'est qu'une étourderie" alors que je m'aperçois que c'était voulu ! Bien vu
Emmanuel Delahaye a écrit : C'est une vielle ficelle de métier, je suis étonné que tu ne la connaisses pas... |
Héhé... on ne peut pas tout connaître...
Marsh Posté le 27-03-2007 à 14:52:29
matafan a écrit : Tu peux contrôler les types en faisant des affectations dans ta macro :
|
Quand on en est à créer un bloc avec son scope, et des variables pour définir le type, on s'approche quand même vachement d'une fonction, il reste quoi comme raison pour ne pas en utiliser une directement ?
Marsh Posté le 27-03-2007 à 15:21:53
0x90 a écrit : Quand on en est à créer un bloc avec son scope, et des variables pour définir le type, on s'approche quand même vachement d'une fonction, il reste quoi comme raison pour ne pas en utiliser une directement ? |
Next step : inline !
Marsh Posté le 27-03-2007 à 18:05:48
Le "do { } while (0)", c'est surtout pour permettre d'utiliser la macro dans un if/else sans bloc, comme on le ferait avec une fonction. Sans le do/while ça donnerait après expansion :
Code :
|
Ce qui ne compile pas puisqu'on a un else sans if. Avec le do/while, ça donne :
Code :
|
Et ça c'est bon.
Marsh Posté le 23-03-2007 à 09:35:36
Bonjour
Je peux lire dans beaucoup de documentations que les macros sont dangereuses parce qu'il n'y a aucun contrôle de type effectué dessus. Je ne comprends pas pourquoi
Si j'ai bien lu le principe des macros, c'est du simple remplacement de texte effectué par le préprocesseur avant compilation. Si je remplace moi même à la main mes appels de macro par le code correspondant, le compilateur effectuera bien un contrôle sur les types ?
Où est la différence?
Où fais je l'erreur?
Message édité par lafourchette le 23-03-2007 à 09:41:11