GCC et SLIG ont un support pour effectuer des vérifications de temps de compilation sur des fonctions d'argument variable telles que sur OSX, le framework de cacao utilise également une extension de ceci pour Dans notre entreprise, nous avons un cadre personnalisé C ++ avec une bande de classes comme J'aimerais effectuer une vérification du temps de compilation des arguments dans nos projets, mais en raison des extensions, existe-t-il un moyen de personnaliser le support de printf code>. Ces compilateurs acceptent la syntaxe comme:
nstring code>: p>
bastion code> tout dérivant de
baseobject code>. Dans
BASESTRING CODE> Il existe quelques méthodes d'argument variable similaires à
Sprintf CODE>, mais avec des extensions. Par exemple,
"% s" code> attend un argument de type
bastion * code> et
"% @" code> attend un
baseObject * Code> Argument. P>
__ attribut __ ((format (printf))) code> donner beaucoup d'avertissements faux positifs. p>
__ attribut __ ((format)) code> pour l'un des deux compilateurs? Si cela nécessite un correctif à la source du compilateur, est-il faisable dans une quantité de temps raisonnable? Alternativement, y a-t-il d'autres outils Lint em> comme des outils pouvant effectuer le chèque? P> p>
4 Réponses :
C'est faisable, mais ce n'est certainement pas facile; Une partie du problème est que La magie est dans la fonction évidemment bien que vous souhaitiez baser votre Le correctif ajouté bassetruction code> et
baseObject code> sont des types définis par l'utilisateur. Vous devez donc définir les spécificateurs de format de manière dynamique. Heureusement, GCC a au moins un support pour cela, mais il faudrait toujours corriger le compilateur.
manipul_format_attribute code> dans
GCC / C-FAMERY / C-FORMAT.C < / Code>, qui appelle les fonctions d'initialisation pour les spécificateurs de format qui font référence aux types définis par l'utilisateur. Un bon exemple pour baser votre support serait le type de format
gcc_gfc code>, car il définit un spécificateur de format
% l code> pour
locus * code>: p>
format_char_info code> tableau sur
print_char_table code>, comme cela définit la norme
printf code> spécificateurs;
gcc_gfc code> est sensiblement réduit en comparaison. p>
gcc_gfc code> est http://gcc.gnu.org/ml/fortran/2005-07/msg00018.html ; Il devrait être assez évident de ce correctif comment et où vous auriez besoin de faire vos ajouts. P> p>
avec une version récente de GCC (je recommande 4.7 ou plus récent, mais vous pouvez essayer avec un GCC 4.6 ) Vous pouvez ajouter vos propres variables et fonctions attributes à travers un plug-in GCC (avec le Si vous utilisez un plugin (E.G. Melt), vous n'aurez pas besoin de recompiler le code source de GCC. Mais vous avez besoin d'un GCC compatible avec plug-in (Vérifier avec En 2020, la FLASE n'est plus mise à jour (en raison du manque de financement); Cependant, vous pouvez écrire votre propre Plugin GCC pour GCC 10 en C ++, faisant de telles vérifications. P>
Certaines distributions Linux ne permettent pas aux plugins dans leur plugin_attributes code> crochet) ou un fondre extension.
Melt est une langue spécifique de domaine pour étendre la GCC (mise en œuvre comme un plug-in [méta-]. P>
GCC -V code>). P>
GCC code> - Veuillez vous plaindre à votre fournisseur de distribution; D'autres fournissent un package pour le développement du plug-in GCC, par ex.
GCC-4.7-Plugin-dev Code> Pour Debian ou Ubuntu. sup> p>
Un an et demi après avoir posé cette question, je suis sorti avec une approche totalement différente pour résoudre le problème réel: existe-t-il un moyen de vérifier statiquement les types d'instructions de formatage de variadiques personnalisées? em> Pour l'exhaustivité et parce que cela peut aider d'autres personnes, voici la solution que j'ai enfin mise en œuvre. Il a deux avantages sur la question initiale: p> Un script Perl analyse le code source, trouve les chaînes de formatage et décode les modificateurs en pourcentage en eux. Il enveloppe ensuite tous les arguments avec un appel à une fonction d'identité de modèle
checkformat code>. Exemple: P>
enum class CFL
{
c, d, i=d, star=i, u, o=u, x=u, X=u, f, F=f, e=f, E=f, g=f, G=f, p, s, S, P=S, at
};
enum class CFM
{
hh, h, l, z, ll, L=ll, _
};
template<CFL letter, CFM modifier, typename T> inline T CheckFormat(T value) { CFL test= value; (void)test; return value; }
template<> inline const BaseString* CheckFormat<CFL::S, CFM::_, const BaseString*>(const BaseString* value) { return value; }
template<> inline const BaseObject* CheckFormat<CFL::at, CFM::_, const BaseObject*>(const BaseObject* value) { return value; }
template<> inline const char* CheckFormat<CFL::s, CFM::_, const char*>(const char* value) { return value; }
template<> inline const void* CheckFormat<CFL::p, CFM::_, const void*>(const void* value) { return value; }
template<> inline char CheckFormat<CFL::c, CFM::_, char>(char value) { return value; }
template<> inline double CheckFormat<CFL::f, CFM::_, double>(double value) { return value; }
template<> inline float CheckFormat<CFL::f, CFM::_, float>(float value) { return value; }
template<> inline int CheckFormat<CFL::d, CFM::_, int>(int value) { return value; }
...
Votre script Perl est-il capable d'analyser le code juridique C ++? D'après mon compréhension, écrivez un outil qui analyse correctement tout le code juridique C ++ est presque aussi difficile que l'écriture d'un compilateur.
@dshin certainement pas, surtout lorsque vous utilisez des macros difficiles. Mais cela fonctionne sans erreur dans notre base de code d'entreprise au moins.
avec C ++ 11, il est possible de résoudre ce problème en remplaçant Voici un croquis de la solution ... p> Si vous avez: p> Vous aurez besoin d'une wrapper macro pour Vous devez écrire __ attribut__ ((Format)) CODE> avec une combinaison intelligente de
consexpr code>,
déclencheur et paquets de paramètres variadic. Passez la chaîne de format dans une fonction
consexpr code> qui extrait tous les spécificateurs
% code> à la compilation et validez que le N'th Specififier correspond au
déclinger code > de l'argument ST (N + 1) 'ST.
my_printf code>, à l'aide du truc décrite ici , pour obtenir quelque chose comme ceci: p>
fmtvalidator code> et
maqueypeholder () code>. p>
Maketypeholder code> va ressembler à ceci: p>
template<>
struct specmatch<int>
{
static constexpr bool match(const char* c, const char* cend)
{
return strmatches(c, cend, "d") ||
strmatches(c, cend, "i");
}
};
// add other specmatch specializations for float, const char*, etc.
Ce commentaire se lit comme le dernier théorème de Fermat. "Il est possible de résoudre ce problème, mais la solution ne convient pas à ce petit espace de commentaire". Pouvez-vous s'il vous plaît élaborer sur votre solution intelligente?
@ Masonfreed Ajouté plus de détails
Agréable! Merci pour la réponse rapide et une réponse détaillée. Particulièrement utile est le Lien à l'autre poste à ce sujet. Malheureusement, je ne pense pas que cette technique fonctionnera pour moi, car je ne peux pas remplacer ma méthode de classe statique existante avec une macro.
Le truc de macro est pratique mais pas nécessaire. Vous pouvez simplement invoquer directement une fonction de validation qui effectue l'affirmation statique.