2013-04-15 1 views
5

Il existe plusieurs implémentations de la fonction printf des modèles variés. L'un est ceci:Modèles variés et types de sécurité

void printf(const char* s) { 
    while (*s) { 
    if (*s == '%' && *++s != '%') 
     throw std::runtime_error("invalid format string: missing arguments"); 
    std::cout << *s++; 
    } 
} 

template<typename T, typename... Args> 
void printf(const char* s, const T& value, const Args&... args) { 
    while (*s) { 
    if (*s == '%' && *++s != '%') { 
     std::cout << value; 
     return printf(++s, args...); 
    } 
    std::cout << *s++; 
    } 
    throw std::runtime_error("extra arguments provided to printf"); 
} 

et partout est dit que cette mise en œuvre est le type de sécurité alors que la normale C (avec des arguments variadique va_arg) n'est pas.

Pourquoi est-ce? Qu'est-ce que cela signifie d'être sécurisé et quels sont les avantages de cette implémentation sur C printf va_arg?

+3

Cette version ne se soucie pas du tout des indicateurs de format, elle imprime simplement des choses à travers les opérateurs de flux. – Xeo

+1

Il est de type sécurisé en ce que 'T' sera toujours le type du paramètre effectivement passé. Le standard printf ne sait pas. –

+1

En aparté, c'est une horrible implémentation 'printf' de typesafe.Il ignore et interprète mal les spécificateurs de format, et ne supporte même pas le déplacement de valeurs temporaires! En résumé, il s'agit d'une fonction de typesafe, mais ce n'est pas une implémentation valide de 'printf', malgré son nom. Un bon type 'printf' se comporterait identiquement à' printf' quand il est sûr, et ne fonctionnerait pas indéfini dans la plupart des cas dangereux. – Yakk

Répondre

4

Être signifie que vous pouvez en toute sécurité ou type sécurisé, de dire regardant le code source si votre programme se comporte correctement.

L'instruction std::cout << x est toujours correcte, en supposant que x a une valeur bien définie (et n'est pas, disons, non initialisée); C'est quelque chose que vous pouvez garantir en regardant le code source.

Par constraste, C est pas sécurité: Par exemple, le code suivant peut ou peut ne pas être correct, en fonction de l'entrée d'exécution:

int main(int argc, char * argv[]) 
{ 
    if (argc == 3) 
     printf(argv[1], argv[2]); 
} 

Cela est vrai si et seulement si le Le premier argument est une chaîne de format valide contenant précisément un "%s". En d'autres termes, il est possible d'écrire un programme C correct, mais il est impossible de raisonner sur l'exactitude juste en inspectant le code. La fonction printf en est un exemple. Plus généralement, toute fonction qui accepte des arguments variables est très probablement dangereuse, comme toute fonction qui place des pointeurs en fonction des valeurs d'exécution.

+0

+1 Difficile de battre cet échantillon pour un meilleur état d'exécution dépendant de l'exécution. Et une excellente réponse en plus de cela. – WhozCraig

5

Pour tous les arguments que vous passez à la version du modèle variadique, leurs types sont connus au moment de la compilation. Cette connaissance est conservée dans la fonction. Chaque objet est ensuite passé à cout avec le très surchargé operator<<. Pour chaque type transmis, il existe une surcharge distincte de cette fonction. En d'autres termes, si vous passez un int, il appelle ostream::operator<<(int), si vous passez un double, il appelle ostream::operator<<(double). Encore une fois, le type est préservé. Et chacune de ces fonctions est spécialisée pour gérer chaque type d'une manière appropriée. C'est la sécurité du type.

Avec le C printf cependant, l'histoire est différente. Le type n'est pas conservé dans la fonction. Il doit le comprendre en fonction du contenu de la chaîne de format (qui peut être une valeur d'exécution). La fonction doit simplement supposer qu'une chaîne de format correcte a été transmise pour correspondre aux types d'arguments. Le compilateur n'applique pas cela.

Il existe également un autre type de sécurité, à savoir le nombre d'arguments. Si vous passez trop peu d'arguments à la fonction C printf, pas assez pour correspondre à la chaîne de format, vous avez un comportement indéfini. Si vous faites la même chose avec le modèle variadique, vous obtenez une exception qui, bien que non souhaitable, est un problème beaucoup plus facile à diagnostiquer.

Questions connexes