Qual é a diferença entre printf () e puts () em C?

176

Eu sei que você pode imprimir com printf()e puts(). Também posso ver que printf()permite interpolar variáveis ​​e formatar.

É puts()apenas uma versão primitiva de printf(). Deve ser usado para todos os possíveis printf()sem interpolação de string?

alex
fonte
1
C / C ++ Respostas
Anthony Forloney
47
Apenas uma observação sobre o uso de printf em vez de puts: nunca, faça um printf(variable)para imprimir uma string. Use puts(variable)ou printf("%s', variable). Há um risco de segurança ao usar uma sequência de formato variável: se a variável puder ser gravada por um invasor, eles poderão atacar o programa usando sequências de formato.
Zan Lynx

Respostas:

141

putsé mais simples que, printfmas lembre-se de que o primeiro anexa automaticamente uma nova linha. Se não é isso que você deseja, você pode fputsusar sua string para usar o stdout printf.

Michael Kristofik
fonte
8
Eu acho que também é importante mencionar os argumentos adicionais que printf leva para adicionar variáveis ​​adicionais na string de saída.
Erutan409
99

(Isso é apontado em um comentário de Zan Lynx, mas acho que merece uma resposta - já que a resposta aceita não o menciona).

A diferença essencial entre puts(mystr);e printf(mystr);é que, no último, o argumento é interpretado como uma sequência de formatação . O resultado geralmente será o mesmo (exceto a nova linha adicionada) se a string não contiver caracteres de controle ( %), mas se você não puder confiar nisso (se mystrfor uma variável em vez de literal), não deverá usá-la.

Portanto, geralmente é perigoso - e conceitualmente errado - passar uma sequência dinâmica como argumento único 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

O mesmo se aplica ao fputsvs fprintf(mas fputsnão adiciona a nova linha).

leonbloy
fonte
De que maneira o uso printf()seria menos eficiente? Em tempo de execução? Em tempo de compilação?
franklin
10
@ franklin em tempo de execução, porque printfprecisa analisar a string de formato. No entanto, isso normalmente deve ser irrelevante. Além disso, um compilador inteligente pode otimizar isso e substituir o printfputs
comando
33

Além da formatação, putsretorna um número inteiro não negativo se for bem-sucedido ou EOFse não for bem- sucedido; while printfretorna o número de caracteres impressos (não incluindo o nulo à direita).

echristopherson
fonte
16

Em casos simples, o compilador converte chamadas printf()em chamadas para puts().

Por exemplo, o código a seguir será compilado no código de montagem que mostro a seguir.

#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

Neste exemplo, usei a versão 4.7.2 do GCC e compilei a fonte gcc -o hello hello.c.

Hannu Balk
fonte
9
E a nova linha que coloca lugares no stdout?
Zubergu 12/09
1
Deveria ter sido printf("Hello world!\n");gcc de fato traduz isso para put. Como é uma mensagem antiga, eu mesma a editarei.
Rafael Almeida
2
Como você leu o código do assembly após compilar o código C?
Koray Tugay
3
@KorayTugay: a -save-tempsopção para gcc faz isso
schaiba
Você também pode usar uma ferramenta como o gdb para desmontar um binário.
Ivan Kaloyanov 24/12/19
10

Certo, printfpoderia ser pensado como uma versão mais poderosa do puts. printffornece a capacidade de formato variáveis para especificadores de formato de saída usando tais como %s, %d, %lf, etc ...

Justin Ethier
fonte
10

Na minha experiência, printf()carrega mais código do que puts()independentemente da string de formato.

Se não precisar de formatação, não o uso printf. No entanto, fwritepara stdouttrabalhar muito mais rápido que puts.

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

Nota: por comentários, '\ 0' é uma constante inteira. A expressão correta deve ser a sizeof(char)indicada pelos comentários.

Thomas Matthews
fonte
2
"fwrite to stdout funciona muito mais rápido que o put." - Qual poderia ser o motivo?
Antony Hatchkins
6
@AntonyHatchkins Normalmente não é "muito" mais rápido. O puts (), no entanto, precisa executar uma chamada strlen () toda vez em sua string, enquanto que se o tamanho for conhecido com fwrite (), ele poderá ser evitado. Esse é praticamente o único contribuidor real para uma diferença de desempenho.
Wiz
8
Esta resposta está incorreta. '\0'tem tipo int, portanto, na maioria dos sistemas, isso será impresso Using fwrit. Se você deseja imprimir uma menor byte, basta usar 1. sizeof (char), que é provável que você pretende aqui, é garantido para ser 1.
Bradley Garagan
8
int puts(const char *s);

puts () grava a string se uma nova linha no stdout.

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

A função printf () grava a saída em stdout, sob o controle de uma sequência de formato que especifica como os argumentos subsequentes são convertidos para a saída.

Usarei esta oportunidade para solicitar que você leia a documentação.

Koray Tugay
fonte
5

a função printf () é usada para imprimir seqüências de caracteres e variáveis ​​na tela, enquanto a função puts () permite imprimir apenas uma sequência na tela.

Wesley Nyandika
fonte
2

puts é a escolha simples e adiciona uma nova linha no final e printf grava a saída de uma sequência formatada.

Consulte a documentação para puts e paraprintf .

Eu recomendaria usar apenas, printfpois isso é mais consistente do que o método de alternância, ou seja, se você estiver depurando, é menos trabalhoso pesquisar todos os printfs que putse printf. Na maioria das vezes você também deseja gerar uma variável em suas impressões, portanto putsé usado principalmente no exemplo de código.

Johan Engblom
fonte
1

Ao comparar puts()e printf(), embora o consumo de memória seja quase o mesmo, puts()leva mais tempo em comparação com printf().

ainda
fonte
Por favor, adicione alguma explicação à sua resposta para que outras pessoas possam aprender com ela - você tem fontes confiáveis ​​para essa reivindicação? Ou algumas razões para explicar essa diferença?
Nico Haase