Quelle est la différence entre printf () et met () en C?

176

Je sais que vous pouvez imprimer avec printf()et puts(). Je peux également voir que cela printf()vous permet d'interpoler des variables et de faire du formatage.

Est puts()simplement une version primitive de printf(). Doit-il être utilisé pour tous les possibles printf()sans interpolation de chaîne?

Alex
la source
48
Juste une note sur l'utilisation de printf au lieu de met: ne jamais, jamais faire un printf(variable)pour imprimer une chaîne. Utilisez puts(variable)ou printf("%s', variable). Il y a un risque de sécurité à utiliser une chaîne de format de variable: si la variable peut être écrite par un attaquant, ils peuvent attaquer le programme en utilisant des chaînes de format.
Zan Lynx

Réponses:

141

putsest plus simple, printfmais sachez que le premier ajoute automatiquement une nouvelle ligne. Si ce n'est pas ce que vous voulez, vous pouvez fputsstdout ou utiliser votre chaîne printf.

Michael Kristofik
la source
8
Je pense qu'il est également important de mentionner les arguments supplémentaires que printf prend pour ajouter des variables supplémentaires dans la chaîne de sortie.
Erutan409
99

(Ceci est souligné dans un commentaire de Zan Lynx, mais je pense que cela mérite une réponse - étant donné que la réponse acceptée ne le mentionne pas).

La différence essentielle entre puts(mystr);et printf(mystr);est que dans ce dernier, l'argument est interprété comme une chaîne de formatage . Le résultat sera souvent le même (sauf pour le saut de ligne ajouté) si la chaîne ne contient aucun caractère de contrôle ( %) mais si vous ne pouvez pas vous fier à cela (si mystrest une variable au lieu d'un littéral), vous ne devez pas l' utiliser.

Donc, il est généralement dangereux - et conceptuellement faux - de passer une chaîne dynamique comme argument unique de printf:

  char * myMessage;
  // ... myMessage gets assigned at runtime, unpredictable content
  printf(myMessage);  // <--- WRONG! (what if myMessage contains a '%' char?) 
  puts(myMessage);    // ok
  printf("%s\n",myMessage); // ok, equivalent to the previous, perhaps less efficient

La même chose s'applique à fputsvs fprintf(mais fputsn'ajoute pas de nouvelle ligne).

Leonbloy
la source
En quoi l'utilisation printf()serait-elle moins efficace? Lors de l'exécution? Au moment de la compilation?
franklin
10
@franklin à l'exécution, car il printfdoit analyser la chaîne de format. Cependant, cela ne devrait normalement pas être pertinent. De plus, un compilateur intelligent pourrait optimiser cela et remplacer l' printfappel àputs
leonbloy
33

Outre le formatage, putsrenvoie un entier non négatif en cas de succès ou d' EOFéchec; while printfrenvoie le nombre de caractères imprimés (sans compter le nul de fin).

echristopherson
la source
16

Dans les cas simples, le compilateur convertit les appels printf()en appels à puts().

Par exemple, le code suivant sera compilé dans le code d'assembly que je montrerai ensuite.

#include <stdio.h>
main() {
    printf("Hello world!");
    return 0;
}
push rbp
mov rbp,rsp
mov edi,str.Helloworld!
call dword imp.puts
mov eax,0x0
pop rbp
ret

Dans cet exemple, j'ai utilisé la version 4.7.2 de GCC et compilé le source avec gcc -o hello hello.c.

Hannu Balk
la source
9
Et qu'en est-il de la nouvelle ligne qui met de la place dans stdout?
zubergu
1
Cela aurait dû être printf("Hello world!\n");gcc qui traduit effectivement cela en put. Puisqu'il s'agit d'un ancien message, je vais le modifier moi-même.
Rafael Almeida
2
Comment avez-vous lu le code d'assemblage après avoir compilé le code C?
Koray Tugay
3
@KorayTugay: l' -save-tempsoption pour gcc fait ça
Schaiba
Vous pouvez également utiliser un outil comme gdb pour désassembler un binaire.
Ivan Kaloyanov
10

Bien, printfpourrait être considéré comme une version plus puissante de puts. printfoffre la possibilité de formats des variables de sortie en utilisant spécificateurs de format tels que %s, %d, %lf, etc ...

Justin Ethier
la source
10

Dans mon expérience, printf()transporte plus de code que puts()quelle que soit la chaîne de format.

Si je n'ai pas besoin du formatage, je ne l'utilise pas printf. Cependant, fwritepour stdoutfonctionne beaucoup plus vite que puts.

static const char my_text[] = "Using fwrite.\n";
fwrite(my_text, 1, sizeof(my_text) - sizeof('\0'), stdout);

Remarque: par commentaire, '\ 0' est une constante entière. L'expression correcte doit être sizeof(char)celle indiquée par les commentaires.

Thomas Matthews
la source
2
"fwrite to stdout fonctionne beaucoup plus vite que les put." - Quelle pourrait être la raison?
Antony Hatchkins
6
@AntonyHatchkins Ce n'est généralement pas "beaucoup" plus rapide. met (), cependant, doit exécuter un appel strlen () à chaque fois sur votre chaîne alors que si la taille est connue avec fwrite (), cela peut être évité. C'est à peu près le seul véritable contributeur à une différence de performance.
Wiz
8
Cette réponse est incorrecte. '\0'a un type int, donc sur la plupart des systèmes, cela s'imprimera Using fwrit. Si vous souhaitez imprimer 1 octet de moins, utilisez simplement 1. sizeof (char), ce qui est probablement ce que vous vouliez ici, est garanti 1.
Bradley Garagan
8
int puts(const char *s);

met () écrit la chaîne s et une nouvelle ligne de fin dans stdout.

int printf(const char *format, ...);

La fonction printf () écrit la sortie dans stdout, sous le contrôle d'une chaîne de format qui spécifie comment les arguments suivants sont convertis pour la sortie.

Je vais profiter de cette occasion pour vous demander de lire la documentation.

Koray Tugay
la source
5

la fonction printf () est utilisée pour imprimer à la fois des chaînes et des variables à l'écran tandis que la fonction put () vous permet uniquement d'imprimer une chaîne uniquement sur votre écran.

Wesley Nyandika
la source
2

putsest le choix simple et ajoute une nouvelle ligne à la fin et printfécrit la sortie à partir d'une chaîne formatée.

Consultez la documentation pour puts et pour printf.

Je recommanderais de l'utiliser uniquement printfcar c'est plus cohérent que la méthode de commutation, c'est-à-dire que si vous déboguez, il est moins difficile de rechercher tous les printfs que putset printf. La plupart du temps, vous souhaitez également afficher une variable dans vos impressions, elle putsest donc principalement utilisée dans le code d'exemple.

Johan Engblom
la source
1

Lorsque vous comparez puts()et printf(), même si leur consommation de mémoire est presque la même, puts()prend plus de temps que printf().

thil
la source
Veuillez ajouter une explication à votre réponse afin que d'autres puissent en tirer des leçons - avez-vous des sources fiables pour cette affirmation? Ou quelques raisons pour expliquer cette différence?
Nico Haase le