Tout d'abord, comme évoqué dans plusieurs autres réponses mais pas, à mon avis, assez clairement expliqué: cela fonctionne pour fournir un entier dans la plupart des contextes où une fonction de bibliothèque prend un argument double
ou float
. Le compilateur insérera automatiquement une conversion. Par exemple, sqrt(0)
est bien défini et se comportera exactement comme sqrt((double)0)
, et il en va de même pour toute autre expression de type entier utilisée ici.
printf
est différent. C'est différent car il prend un nombre variable d'arguments. Son prototype de fonction est
extern int printf(const char *fmt, ...);
Par conséquent, lorsque vous écrivez
printf(message, 0);
le compilateur n'a aucune information sur le type printf
attendu de ce second argument. Il n'a que le type de l'expression d'argument, qui est int
, pour passer. Par conséquent, contrairement à la plupart des fonctions de bibliothèque, c'est à vous, le programmeur, de vous assurer que la liste d'arguments correspond aux attentes de la chaîne de format.
(Les compilateurs modernes peuvent examiner une chaîne de format et vous dire que vous avez une incompatibilité de type, mais ils ne vont pas commencer à insérer des conversions pour accomplir ce que vous vouliez dire, car mieux votre code devrait se casser maintenant, quand vous le remarquerez , que des années plus tard lors de la reconstruction avec un compilateur moins utile.)
Maintenant, l'autre moitié de la question était: étant donné que (int) 0 et (float) 0.0 sont, sur la plupart des systèmes modernes, tous deux représentés comme 32 bits qui sont tous à zéro, pourquoi ne fonctionne-t-il pas de toute façon, par accident? La norme C dit simplement "cela n'est pas nécessaire pour fonctionner, vous êtes seul", mais laissez-moi vous expliquer les deux raisons les plus courantes pour lesquelles cela ne fonctionnerait pas; cela vous aidera probablement à comprendre pourquoi ce n'est pas nécessaire.
Tout d' abord, pour des raisons historiques, lorsque vous passez une float
par une liste d'arguments variable , il se promu à double
qui, sur la plupart des systèmes modernes, est 64 bits. Donc printf("%f", 0)
passe seulement 32 bits de zéro à un appelé qui en attend 64.
La deuxième raison, tout aussi significative, est que les arguments de fonction à virgule flottante peuvent être passés à un endroit différent des arguments entiers. Par exemple, la plupart des processeurs ont des fichiers de registre séparés pour les entiers et les valeurs à virgule flottante, il se peut donc que les arguments 0 à 4 soient placés dans les registres r0 à r4 s'ils sont des entiers, mais f0 à f4 s'ils sont à virgule flottante. printf("%f", 0)
Cherche donc dans le registre f1 ce zéro, mais il n'y est pas du tout.
printf
attend undouble
, et vous lui donnez unint
.float
etint
peut être de la même taille sur votre machine, mais0.0f
est en fait converti en undouble
lorsqu'il est poussé dans une liste d'arguments variadiques (et il s'yprintf
attend). En bref, vous ne remplissez pas votre part du marché enprintf
fonction des spécificateurs que vous utilisez et des arguments que vous fournissez.