La sortie est différente en raison de l'ordre dans lequel le préprocesseur fait les choses, ce qui est décrit dans la section 6.10.3 (et suivantes) dans la norme C99. cette phrase de 6.10.3.1/1 en particulier:
Un paramètre dans la liste de remplacement, si elle est précédée d'un jeton ou suivi d'un jeton ##
prétraiter prétraiter #
ou ##
, est remplacé par l'argument correspondant après tout les macros qui y sont contenues ont été étendues.
Ainsi, dans la première ligne, lors de l'expansion de l'invocation h
, l'argument f(1,2)
est dilatée avant remplace le paramètre de h
a
. Le #
n'intervient que plus tard lorsque l'invocation de g
qui en résulte est vue lorsque la sortie de tout ce qui est resynchronisé.
Mais sur la deuxième ligne, le #
est vu immédiatement et la clause "sauf précédé par ..." de la citation ci-dessus déclenche le comportement différent.
Voir aussi the relevant C-FAQ entry.