c'est lié à la façon dont le pré-processeur traite l'ordre des substitutions
vous voulez fabriquer
#pragma message("freq cpu: 16000000L")
F_CPU est un define fourni sur la ligne de compilation par -DF_CPU=16000000L et donc ce n'est pas une chaîne de caractère (il n'a pas les guillemets).
Subtilité du langage, on a le droit de mettre deux chaînes côte à côte pour en faire une complète donc on peut aussi écrire (et avoir à bâtir):
#pragma message("freq cpu:" "16000000L")
pour obtenir des guillemets autour de F_CPU, il y a une commande du pré-processeur qui traite cela : le symbole # dans une macro, c'est l'objet de:
#define STRING2(x) #x
On pourrait donc se dire qu'il suffirait d'écrire
#pragma message ("freq cpu: " STRING2(F_CPU))
et le tour serait joué.. Mais manque de bol, si on fait cela, on obtient
#pragma message("freq cpu: " "F_CPU")
parce que l'ordre de substitution tient au standard qui définit les "macro replacement"
In function-like macros, a # operator before an identifier in the replacement-list runs the identifier through parameter replacement and encloses the result in quotes, effectively creating a string literal
maintenant si on crée la double indirection, au premier passage du pré-processeur on n'a plus le # et on obtient
#pragma message ("freq cpu: " STRING2(16000000L))
car tous les define on été replacés une fois. Puis le pré-processeur voit qu'on a encore une macro (STRING2) et donc redonne un coup de substitution et on obtient bien ce que l'on cherchait à bâtir:
#pragma message ("freq cpu: " "16000000L")