J'utilise la fonction sprintf
en C++ 11, de la manière suivante:
std::string toString()
{
std::string output;
uint32_t strSize=512;
do
{
output.reserve(strSize);
int ret = sprintf(output.c_str(), "Type=%u Version=%u ContentType=%u contentFormatVersion=%u magic=%04x Seg=%u",
INDEX_RECORD_TYPE_SERIALIZATION_HEADER,
FORAMT_VERSION,
contentType,
contentFormatVersion,
magic,
segmentId);
strSize *= 2;
} while (ret < 0);
return output;
}
Y a-t-il un meilleur moyen de le faire que de vérifier chaque fois si l'espace réservé était suffisant? Pour la possibilité future d'ajouter plus de choses.
Votre construction - write dans le tampon reçu de c_str()
- est un comportement non défini , même si vous avez préalablement vérifié la capacité de la chaîne. (La valeur de retour est un pointeur sur const char et la fonction elle-même marquée const pour une raison.)
Ne mélangez pas C et C++, spécialement, pas pour écrire dans la représentation d'objet interne. (Cela rompt une OOP très basique.) Utilisez C++, pour la sécurité de type et ne courez pas dans des incompatibilités spécificateur/paramètre de conversion, si rien d'autre.
std::ostringstream s;
s << "Type=" << INDEX_RECORD_TYPE_SERIALIZATION_HEADER
<< " Version=" << FORMAT_VERSION
// ...and so on...
;
std::string output = s.str();
Alternative:
std::string output = "Type=" + std::to_string( INDEX_RECORD_TYPE_SERIALIZATION_HEADER )
+ " Version=" + std::to_string( FORMAT_VERSION )
// ...and so on...
;
Les modèles C++ montrés dans les autres réponses sont plus agréables, mais pour être complet, voici une manière correcte avec sprintf
:
auto format = "your %x format %d string %s";
auto size = std::snprintf(nullptr, 0, format /* Arguments go here*/);
std::string output(size + 1, '\0');
std::sprintf(&output[0], format, /* Arguments go here*/);
Faire attention à
resize
votre chaîne. reserve
ne modifie pas la taille du tampon. Dans mon exemple, je construis directement une chaîne correctement dimensionnée.c_str()
renvoie un const char*
. Vous ne pouvez pas le transmettre à sprintf
.std::string
Il n'était pas garanti que la mémoire tampon soit contiguë avant C++ 11 et cela repose sur cette garantie. Si vous devez prendre en charge des plates-formes exotiques conformes à std::string
et conformes à la version antérieure à C++ 11, il est probablement préférable de commencer par sprinting dans std::vector<char>
puis de copier le vecteur dans la chaîne.Nous pouvons mélanger le code à partir d'ici https://stackoverflow.com/a/36909699/2667451 et ici https://stackoverflow.com/a/7257307 et le résultat sera comme ça:
template <typename ...Args>
std::string stringWithFormat(const std::string& format, Args && ...args)
{
auto size = std::snprintf(nullptr, 0, format.c_str(), std::forward<Args>(args)...);
std::string output(size + 1, '\0');
std::sprintf(&output[0], format.c_str(), std::forward<Args>(args)...);
return output;
}
Votre code est faux. reserve
alloue de la mémoire pour la chaîne, mais ne modifie pas sa taille. L'écriture dans le tampon renvoyé par c_str
ne modifie pas non plus sa taille. Donc, la chaîne croit toujours que sa taille est 0 et que vous venez d'écrire quelque chose dans l'espace inutilisé du tampon de la chaîne. (Probablement. Techniquement, le code a un comportement indéfini, car l'écriture dans c_str
est indéfinie, donc tout peut arriver).
Ce que vous voulez vraiment faire, c'est oublier sprintf
et des fonctions similaires à celles du style C et utiliser la méthode de formatage de chaîne C++ - flux de chaînes:
std::ostringstream ss;
ss << "Type=" << INDEX_RECORD_TYPE_SERIALIZATION_HEADER
<< " Version=" << FORAMT_VERSION
<< /* ... the rest ... */;
return ss.str();
Oui il y a!
En C, la meilleure solution consiste à associer un fichier au périphérique null et à créer une variable factice printf
de la sortie souhaitée, pour savoir combien d’espace prendrait l’impression. Allouez ensuite le tampon approprié et sprintf
les mêmes données.
En C++, vous pouvez également associer le flux de sortie à un périphérique null et tester le nombre de caractères imprimés avec std :: ostream :: tellp . Cependant, utiliser ostringstream
est une solution plus efficace - voir les réponses de DevSolar ou Angew.