2010-07-20 6 views
1

J'ai ce code dans un constructeur d'une classe (pas écrit par moi) et il écrit une liste d'arguments variable dans un fichier tmp.var arg liste au fichier temporaire, pourquoi est-il nécessaire?

Je me demandais pourquoi cela serait nécessaire? Le tmpfile est supprimé après que ce ctor est hors de portée et la liste d'arguments var se trouve dans le vecteur m_str. Quelqu'un peut-il suggérer une meilleure façon de le faire sans l'utilisation d'un tmpfile?

DString(const char *fmt, ...) 
    { 

     DLog::Instance()->Log("Inside DString with ellipses"); 

     va_list varptr; 
     va_start(varptr, fmt); 
     FILE *f = tmpfile(); 
     if (f != NULL) 
     { 
      int n = ::vfprintf(f, fmt, varptr) + 1; 
      m_str.resize(n + 1); 
      ::vsprintf(&m_str[0], fmt, varptr); 
      va_end(varptr); 
     } 
     else 
      DLog::Instance()->Log("[ERROR TMPFILE:] Unable to create TmpFile for request!"); 
    } 
+0

Pouvez-vous changer le prototype du constructeur pour éviter d'utiliser des ellipses? – ereOn

+0

ereOn: Aucune cause Cela causerait beaucoup d'erreurs dans mon code. –

+0

Si 'm_str' est un' std :: string', alors traiter '& m_str [0]' comme un pointeur sur un tableau donne un comportement indéfini; le stockage n'est pas garanti contigu.Si c'est un 'std :: vector ', alors c'est OK. –

Répondre

2

Ceci est le code C++: Je pense que vous pouvez essayer de résoudre le mauvais problème.

Le besoin d'un fichier temporaire disparaîtrait complètement si vous envisagez d'utiliser un design C++-esque au lieu de continuer à utiliser les varargs. Cela peut sembler beaucoup de travail de convertir tous les sites d'appel pour utiliser un nouveau mécanisme, mais les varargs offrent une grande variété de possibilités de mal-passer les paramètres vous laissant ouvert aux bugs insidieux, sans parler du fait que vous ne pouvez pas passer Types de POD du tout. Je crois que le long terme (ou même le moyen terme) sera payant en termes de fiabilité, de clarté et de facilité de débogage. Au lieu de cela, essayez d'implémenter une interface de flux de style C++ qui fournit la sécurité du type et même la possibilité d'interdire certaines opérations si nécessaire.

1

Il est juste en utilisant le fichier temporaire comme un endroit où il peut écrire le contenu qui ne déborde pas, il peut donc mesurer la longueur, puis allouer suffisamment d'espace pour la chaîne, et enfin déposer la production réelle la chaîne

je considérer au moins combien il serait difficile de remplacer l'interface actuelle de style printf qui est conduit à cela avec une interface iostreams de style, ce qui rendra facile à éviter et donnent tous les avantages habituels de iostreams (type sécurisé, extensible, etc.)

Modifier: si le changement de la signature de la fonction est vraiment trop difficile à envisager, alors vous voulez probablement remplacer vfprintf par vsnprintf. vsnprintf vous permet de spécifier une longueur de tampon (de sorte qu'il ne dépassera pas le tampon) et il retourne le nombre de caractères que auraient été générés s'il y avait suffisamment d'espace. En tant que tel, l'utilisation serait presque comme vous avez maintenant, mais évitez de générer le fichier temporaire. Vous l'appelez une fois en spécifiant une longueur de tampon de 0, utilisez la valeur de retour (+1 pour le terminateur NUL) pour redimensionner votre tampon, puis rappelez-le en spécifiant la taille de tampon correcte.

+0

Est-il remplaçable sans changer la signature de ce constructeur? –

+0

@Tony: oui. 'n = vsnprintf (0, 0, fmt, varptr) + 1' vous donnera la longueur sans flapper avec des fichiers temporaires. –

0

Il semble utiliser le fichier temporaire comme un emplacement de sortie pour l'appel :: vfprintf(). Il le fait pour obtenir la longueur de la chaîne formatée (plus 1 pour la valeur NULL). Puis redimensionne m_str assez grand pour contenir la chaîne formatée, qui est remplie à partir de l'appel :: vsprintf().

La liste var arg ne se trouve pas dans le fichier ou dans m_str. La sortie formatée de printf() (et ses variantes) se trouve dans le fichier et dans m_str.

0

J'ai un sentiment nauséeux montrant cela, mais vous pouvez essayer:

FILE *fp=freopen("nul","w", stderr) 
    int n = ::vfprintf(fp , fmt, varptr); 
    fclose(fp); 

(fenêtres)

Questions connexes