__printflike__ modificateur

qu’est-ce que “__printflike__ modificateur” exactement? Que signifie ce terme?

En un mot, il indique au compilateur que vous utilisez qu’une fonction prend des arguments sous la forme [anything, ] format, ... où le format, ... partie format, ... ressemblent aux arguments de printf . L’atsortingbut __printflike__ permet au compilateur de tester les types de la liste d’arguments par rapport au format de chaîne. Cela se produit lorsque vous écrivez une fonction comme log(format, ...) et utilisez vsprintf pour subordonner le travail de formatage aux fonctions de bibliothèque standard habituelles avant d’envoyer la chaîne à une interface de journal spéciale.

Si vous utilisez GCC, il s’agit probablement d’une #define dans votre projet, quelque chose comme:

 #define __printflike__ __atsortingbute__((format(printf, 1, 2))) 

1, 2 signifie que le format, ... apparaît aux positions 1 et 2.

J’ai une fonction dans ma bibliothèque de rapports d’erreur avec la déclaration dans l’en-tête comme:

 extern void err_logmsg(FILE *fp, int flags, int estat, const char *format, ...) PRINTFLIKE(4,5); 

Le PRINTFLIKE est en majuscule afin que je puisse le définir comme rien lorsque je n’utilise pas GCC. Cette utilisation indique que les trois premiers arguments n’ont rien de spécial, mais le quasortingème argument est une chaîne de format semblable à celle utilisée par printf() (en fait, elle est transmise à vfprintf() ) et en utilisant la chaîne de format) commence par le cinquième argument.

Cela signifie que si je tape:

 err_logmsg(stdout, ERR_ABORT, 1, "%s: %d\n", errno, strerror(errno)); 

Je vais avoir une erreur de compilation parce que errno est un strerror(errno) et strerror(errno) renvoie un pointeur sur une chaîne. Je peux corriger l’erreur en modifiant la chaîne de format ou les cinquième et sixième arguments. (ERR_ABORT est un ensemble d’indicateurs défini dans le même en-tête qui déclare err_logmsg() .)

La macro PRINTFLIKE contient deux nombres, car il peut exister d’autres arguments entre la chaîne de formatage et le premier des arguments utilisés par la chaîne de formatage. Par exemple, une fonction alternative pourrait être:

 extern void err_writer(FILE *fp, const char *format, int flags, int estat, ...) PRINTFLIKE(2,5); 

Cela indique au compilateur que la chaîne de formatage est le deuxième argument, mais que les arguments correspondants formatés apparaissent toujours à partir du cinquième argument.

Le fichier d’en-tête de ce code contient les lignes:

 #ifdef __GNUC__ #define PRINTFLIKE(n,m) __atsortingbute__((format(printf,n,m))) #define NORETURN() __atsortingbute__((noreturn)) #else #define PRINTFLIKE(n,m) /* If only */ #define NORETURN() /* If only */ #endif /* __GNUC__ */ 

Indique probablement au compilateur que la fonction correspondante a une sémantique semblable à printf .

Cela peut permettre au compilateur d’émettre des avertissements au moment de la compilation lorsque les modificateurs de la chaîne de format ne correspondent pas au type ou au nombre d’arguments transmis.

Le compilateur ne dispose d’aucun autre moyen de savoir que %u n’est pas la bonne mise en forme pour un int lorsque vous appelez printf , sprintf , fprintf , etc.

J’ai posé la question inverse il y a quelques mois: les avertissements du compilateur printf / sprintf sont-ils une rupture conceptuelle?