206 votes

Comment utiliser printf avec std :: string

Ma compréhension est que string est un membre de l'espace de noms std, alors pourquoi se produit-il ce qui suit?

#include 

int main()
{
    using namespace std;

    string myString = "Appuyez sur ENTRER pour quitter le programme!";
    cout << "Venez me dire bonjour en C++." << endl;
    printf("Suivez cette commande: %s", myString);
    cin.get();

    return 0;
}

description de l'image ici

Chaque fois que le programme est exécuté, myString imprime une chaîne de 3 caractères apparemment aléatoire, comme dans la sortie ci-dessus.

8 votes

Juste pour que vous le sachiez, beaucoup de gens critiquent ce livre. Ce que je peux comprendre, car il n'y a pas grand-chose sur la programmation orientée objet, mais je ne pense pas que ce soit aussi mauvais que ce que les gens prétendent.

0 votes

Ouf! eh bien, c'est bon de garder cela à l'esprit pendant que je parcours le livre. Je suis sûr que ce ne sera pas le seul livre en C++ que je lirai au cours de l'année prochaine ou plus, donc j'espère qu'il ne fera pas trop de dégâts :)

0 votes

En utilisant le niveau d'avertissement le plus élevé du compilateur répondrait à votre question - lors de la compilation avec gcc. Comment MSVC gère cela - je ne sais pas.

2voto

Hyena Points 59

printf accepte un nombre variable d'arguments. Ceux-ci ne peuvent avoir que des types de données Plain Old Data (POD). Le code qui passe autre chose que des POD à printf ne compile que parce que le compilateur suppose que vous avez bien fait votre format. %s signifie que l'argument correspondant doit être un pointeur vers un char. Dans votre cas, il s'agit d'une std::string et non d'un const char*. printf n'est pas au courant car le type d'argument se perd et doit être restauré à partir du paramètre de format. Lorsque cet argument std::string est transformé en const char*, le pointeur résultant pointera vers une région de mémoire non pertinente au lieu de votre chaîne C désirée. Pour cette raison, votre code affiche des absurdités.

Alors que printf est un excellent choix pour afficher du texte formaté, (surtout si vous prévoyez d'avoir du padding), il peut être dangereux si vous n'avez pas activé les avertissements du compilateur. Activez toujours les avertissements car ainsi des erreurs comme celle-ci sont facilement évitables. Il n'y a aucune raison d'utiliser le mécanisme maladroit de std::cout si la famille printf peut faire la même tâche de manière beaucoup plus rapide et plus jolie. Assurez-vous simplement d'avoir activé tous les avertissements (-Wall -Wextra) et vous serez bon. Si vous utilisez votre propre implémentation personnalisée de printf, vous devriez la déclarer avec le mécanisme __attribute__ qui permet au compilateur de vérifier la chaîne de format par rapport aux paramètres fournis.

1voto

MMacD Points 339

La principale raison est probablement qu'une chaîne C++ est une structure qui inclut une valeur de longueur actuelle, et non simplement l'adresse d'une séquence de caractères terminée par un octet 0. Printf et ses membres s'attendent à trouver une telle séquence et non une structure, et sont donc déconcertés par les chaînes C++.

En ce qui me concerne, je crois que printf a une place qui ne peut pas être facilement comblée par les fonctionnalités syntaxiques de C++, tout comme les structures de table en html ont une place qui ne peut pas être facilement remplacée par des divs. Comme Dykstra l'a écrit plus tard à propos du goto, il n'avait pas l'intention de créer une religion et ne faisait réellement que prôner contre son utilisation comme rustine pour pallier les lacunes du code mal conçu.

Ce serait très bien si le projet GNU ajoutait la famille printf à leurs extensions g++.

1voto

QuentinUK Points 995

Voici une manière générique de le faire.

#include 
#include 

auto print_helper(auto const & t){
    return t;
}
auto print_helper(std::string const & s){
    return s.c_str();
}
std::string four(){
    return "four";
}
template
void print(char const * fmt, Args&& ...args){
    printf(fmt, print_helper(args) ...);
}
int main(){
    std::string one {"one"};
    char const * three = "three";
    print("%c %d %s %s, %s five", 'c', 3+4, one + " two", three, four());
}

0voto

howard howard Points 35

Printf est en fait assez bon à utiliser si la taille est importante. Cela signifie que si vous exécutez un programme où la mémoire est un problème, alors printf est en fait une solution très bonne et sous-estimée. Cout déplace essentiellement des bits pour faire de la place pour la chaîne, alors que printf prend simplement certains paramètres et les affiche à l'écran. Si vous deviez compiler un simple programme de bonjour monde, printf pourrait le compiler en moins de 60 000 bits alors que cout prendrait plus d'un million de bits pour compiler.

Pour votre situation, je vous suggère d'utiliser cout simplement parce qu'il est beaucoup plus pratique à utiliser. Cependant, je soutiendrais que printf est quelque chose de bon à connaître.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X