Estou surpreso que todos nesta pergunta afirmem que std::cout
é muito melhor do que printf
, mesmo que a pergunta apenas peça diferenças. Agora, há uma diferença - std::cout
é C ++ e printf
C (no entanto, você pode usá-lo em C ++, assim como quase qualquer outra coisa em C). Agora, vou ser sincero aqui; ambos printf
e std::cout
têm suas vantagens.
std::cout
é extensível. Eu sei que as pessoas dirão que printf
é extensível também, mas essa extensão não é mencionada no padrão C (então você teria que usar recursos não-padrão - mas nem mesmo um recurso não-padrão comum existe), e essas extensões são uma letra (é fácil entrar em conflito com um formato já existente).
Ao contrário printf
, std::cout
depende completamente da sobrecarga do operador, portanto não há problema com formatos personalizados - tudo o que você faz é definir uma sub-rotina que assuma std::ostream
o primeiro argumento e seu tipo como o segundo. Como tal, não há problemas no espaço para nome - contanto que você tenha uma classe (que não se limita a um caractere), poderá trabalharstd::ostream
sobrecarga nela.
No entanto, duvido que muitas pessoas desejem estender ostream
(para ser sincero, raramente vi essas extensões, mesmo que sejam fáceis de fazer). No entanto, está aqui se você precisar.
Como pode ser facilmente percebido, ambos printf
e std::cout
usam sintaxe diferente. printf
usa sintaxe de função padrão usando seqüência de caracteres padrão e listas de argumentos de comprimento variável. Na verdade, printf
é uma razão pela qual C os possui - os printf
formatos são complexos demais para serem utilizáveis sem eles. No entanto, std::cout
usa uma API diferente - a operator <<
API que retorna automaticamente.
Geralmente, isso significa que a versão C será mais curta, mas na maioria dos casos não importa. A diferença é perceptível quando você imprime muitos argumentos. Se você precisar escrever algo como Error 2: File not found.
, assumindo o número do erro, e sua descrição for um espaço reservado, o código seria assim. Ambos os exemplos funcionam de forma idêntica (bem, std::endl
na verdade , libera o buffer).
printf("Error %d: %s.\n", id, errors[id]);
std::cout << "Error " << id << ": " << errors[id] << "." << std::endl;
Embora isso não pareça muito louco (são apenas duas vezes mais), as coisas ficam mais loucas quando você formata argumentos, em vez de apenas imprimi-los. Por exemplo, imprimir algo assim 0x0424
é simplesmente louco. Isso é causado pela std::cout
mistura do estado e dos valores reais. Eu nunca vi uma linguagem em que algo std::setfill
desse tipo fosse um tipo (além de C ++, é claro). printf
separa claramente argumentos e tipo real. Eu realmente preferiria manter a printf
versão dele (mesmo que pareça meio enigmática) em comparação com a iostream
versão dele (pois contém muito ruído).
printf("0x%04x\n", 0x424);
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(4) << 0x424 << std::endl;
É aqui que a verdadeira vantagem das printf
mentiras. A printf
string de formato está bem ... uma string. Isso facilita muito a tradução, comparado ao operator <<
abuso de iostream
. Supondo que a gettext()
função seja traduzida e você queira mostrar Error 2: File not found.
, o código para obter a tradução da string de formato mostrada anteriormente ficaria assim:
printf(gettext("Error %d: %s.\n"), id, errors[id]);
Agora, vamos supor que traduzimos para ficcional, onde o número do erro está após a descrição. A string traduzida seria semelhante %2$s oru %1$d.\n
. Agora, como fazer isso em C ++? Bem, eu não tenho ideia. Eu acho que você pode falsificar iostream
quais construções printf
você pode passar gettext
, ou algo assim, para fins de tradução. Claro,$
não é padrão C, mas é tão comum que é seguro usá-lo na minha opinião.
C tem muitos tipos de números inteiros, e o C ++ também. std::cout
lida com todos os tipos para você, enquanto printf
requer uma sintaxe específica, dependendo de um tipo inteiro (existem tipos não inteiros, mas o único tipo não inteiro com o qual você utilizará na prática printf
é is const char *
(cadeia C, pode ser obtida usando o to_c
método de std::string
)). Por exemplo, para imprimir size_t
, você precisa usar %zd
, enquanto int64_t
exigirá o uso %"PRId64"
. As tabelas estão disponíveis em http://en.cppreference.com/w/cpp/io/c/fprintf e http://en.cppreference.com/w/cpp/types/integer .
\0
Como printf
usa seqüências de caracteres C em vez de seqüências de caracteres C ++, ele não pode imprimir bytes NUL sem truques específicos. Em certos casos, é possível usar %c
com'\0'
como um argumento, apesar de que é claramente um hack.
Atualização: Acontece que iostream
é tão lento que geralmente é mais lento que o seu disco rígido (se você redirecionar o programa para o arquivo). Desabilitar a sincronização com stdio
pode ajudar, se você precisar gerar muitos dados. Se o desempenho for uma preocupação real (em vez de escrever várias linhas no STDOUT), basta usar printf
.
Todo mundo pensa que se importa com o desempenho, mas ninguém se incomoda em mensurá-lo. Minha resposta é que a E / S é um gargalo de qualquer maneira, não importa se você usa printf
ou iostream
. Eu acho que printf
poderia ser mais rápido desde uma rápida olhada no assembly (compilado com clang usando a -O3
opção do compilador). Assumindo o meu exemplo de erro, o printf
exemplo faz muito menos chamadas que o cout
exemplo. Isto é int main
com printf
:
main: @ @main
@ BB#0:
push {lr}
ldr r0, .LCPI0_0
ldr r2, .LCPI0_1
mov r1, #2
bl printf
mov r0, #0
pop {lr}
mov pc, lr
.align 2
@ BB#1:
Você pode perceber facilmente que duas seqüências de caracteres e 2
(número) são enviadas como printf
argumentos. É sobre isso; Não há mais nada. Para comparação, isso é iostream
compilado para montagem. Não, não há inlining; toda operator <<
chamada significa outra chamada com outro conjunto de argumentos.
main: @ @main
@ BB#0:
push {r4, r5, lr}
ldr r4, .LCPI0_0
ldr r1, .LCPI0_1
mov r2, #6
mov r3, #0
mov r0, r4
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
mov r0, r4
mov r1, #2
bl _ZNSolsEi
ldr r1, .LCPI0_2
mov r2, #2
mov r3, #0
mov r4, r0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r1, .LCPI0_3
mov r0, r4
mov r2, #14
mov r3, #0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r1, .LCPI0_4
mov r0, r4
mov r2, #1
mov r3, #0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr r0, [r4]
sub r0, r0, #24
ldr r0, [r0]
add r0, r0, r4
ldr r5, [r0, #240]
cmp r5, #0
beq .LBB0_5
@ BB#1: @ %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit
ldrb r0, [r5, #28]
cmp r0, #0
beq .LBB0_3
@ BB#2:
ldrb r0, [r5, #39]
b .LBB0_4
.LBB0_3:
mov r0, r5
bl _ZNKSt5ctypeIcE13_M_widen_initEv
ldr r0, [r5]
mov r1, #10
ldr r2, [r0, #24]
mov r0, r5
mov lr, pc
mov pc, r2
.LBB0_4: @ %_ZNKSt5ctypeIcE5widenEc.exit
lsl r0, r0, #24
asr r1, r0, #24
mov r0, r4
bl _ZNSo3putEc
bl _ZNSo5flushEv
mov r0, #0
pop {r4, r5, lr}
mov pc, lr
.LBB0_5:
bl _ZSt16__throw_bad_castv
.align 2
@ BB#6:
No entanto, para ser honesto, isso não significa nada, pois a E / S é o gargalo de qualquer maneira. Eu só queria mostrar queiostream
não é mais rápido porque é "tipo seguro". A maioria das implementações de C implementa printf
formatos usando goto computado, de modo que printf
é o mais rápido possível, mesmo sem o compilador estar ciente printf
(não que eles não estejam - alguns compiladores podem otimizar printf
em certos casos) - as constantes que terminam com \n
geralmente são otimizadas paraputs
) .
Não sei por que você gostaria de herdar ostream
, mas não me importo. Também é possível com FILE
.
class MyFile : public FILE {}
É verdade que as listas de argumentos de comprimento variável não têm segurança, mas isso não importa, pois os compiladores C populares podem detectar problemas com a printf
sequência de formato se você ativar avisos. De fato, o Clang pode fazer isso sem ativar avisos.
$ cat safety.c
#include <stdio.h>
int main(void) {
printf("String: %s\n", 42);
return 0;
}
$ clang safety.c
safety.c:4:28: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
printf("String: %s\n", 42);
~~ ^~
%d
1 warning generated.
$ gcc -Wall safety.c
safety.c: In function ‘main’:
safety.c:4:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("String: %s\n", 42);
^
std::sort
, que é surpreendentemente rápido em comparação comqsort
(2 vezes), em custo do tamanho do executável).No FAQ do C ++ :
Por outro lado,
printf
é significativamente mais rápido, o que pode justificar usá-lo de preferênciacout
em casos muito específicos e limitados. Sempre perfil primeiro. (Veja, por exemplo, http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-cout /)fonte
printf()
também é suposto ser extensível. Veja "printf hooks" em udrepper.livejournal.com/20948.htmlprintf
não tem essa capacidade. Mecanismos de biblioteca não portáteis dificilmente estão no mesmo nível da extensibilidade totalmente padronizada dos iostreams.As pessoas costumam afirmar que
printf
é muito mais rápido. Isso é em grande parte um mito. Acabei de o testar, com os seguintes resultados:Conclusão: se você deseja apenas novas linhas, use
printf
; caso contrário,cout
é quase tão rápido ou até mais rápido. Mais detalhes podem ser encontrados no meu blog .Para deixar claro, não estou tentando dizer que
iostream
s são sempre melhores queprintf
; Estou apenas tentando dizer que você deve tomar uma decisão informada com base em dados reais, não um palpite selvagem, com base em alguma suposição comum e enganosa.Atualização: Aqui está o código completo que usei para testar. Compilado
g++
sem opções adicionais (além do-lrt
tempo).fonte
printf()
estd::ostream
é que o primeiro gera todos os argumentos em uma única chamada, ao passo questd::ostream
gera uma chamada separada para cada um<<
. O teste gera apenas um argumento e uma nova linha, é por isso que você não vê a diferença.printf
pode fazer muitas chamadas sob as cobertas para funções auxiliares para vários especificadores de formatação ... isso, ou é uma função monolítica monstruosa. E, novamente, por causa do inline, não deve fazer diferença na velocidade.sprintf
oufprintf
estringstream
oufstream
.E cito :
fonte
Uma é uma função que imprime no stdout. O outro é um objeto que fornece várias funções de membro e sobrecargas
operator<<
dessa impressão para stdout. Eu poderia enumerar muitas outras diferenças, mas não tenho certeza do que você está procurando.fonte
Para mim, as diferenças reais que me levariam a cout em vez de 'printf' são:
1) << operador pode ser sobrecarregado para minhas classes.
2) O fluxo de saída do cout pode ser facilmente alterado para um arquivo: (: copy paste :)
3) Acho que o cout é mais legível, principalmente quando temos muitos parâmetros.
Um problema
cout
é com as opções de formatação. Formatar os dados (precisão, justificativa etc.)printf
é mais fácil.fonte
printf
para um arquivo, substituindo-o porfprintf
...Dois pontos não mencionados aqui que considero significativos:
1)
cout
carrega muita bagagem se você ainda não estiver usando o STL. Ele adiciona mais de duas vezes mais código ao seu arquivo de objeto queprintf
. Isso também é verdadestring
, e esse é o principal motivo pelo qual eu uso minha própria biblioteca de strings.2)
cout
usa<<
operadores sobrecarregados , o que acho infeliz. Isso pode causar confusão se você também estiver usando o<<
operador para a finalidade a que se destina (pressione a esquerda). Pessoalmente, não gosto de sobrecarregar os operadores para fins tangenciais ao uso pretendido.Conclusão: usarei
cout
(estring
) se já estiver usando o STL. Caso contrário, eu tendem a evitá-lo.fonte
Com os primitivos, provavelmente não importa totalmente qual deles você usa. Eu digo que é útil quando você deseja gerar objetos complexos.
Por exemplo, se você tem uma aula,
Agora, o que foi dito acima pode não parecer tão bom, mas vamos supor que você precise produzi-lo em vários locais do seu código. Além disso, digamos que você adicione um campo "int d". Com cout, você só precisa trocá-lo uma vez. No entanto, com o printf, você teria que alterá-lo em vários lugares, e não apenas isso, você deve se lembrar quais devem ser impressos.
Dito isso, com o cout, é possível reduzir muito tempo gasto com a manutenção do seu código e não apenas se você reutilizar o objeto "Algo" em um novo aplicativo, não precisa se preocupar com a saída.
fonte
Claro que você pode escrever "algo" um pouco melhor para manter a manutenção:
E um teste um pouco estendido de cout vs. printf, adicionou um teste de 'double', se alguém quiser fazer mais testes (Visual Studio 2008, versão de lançamento do executável):
O resultado é:
fonte
endl
tão menos eficiente que'\n'
?endl
libera o buffer, e\n
não, embora não tenha certeza de que esse seja definitivamente o motivo.Gostaria de salientar que, se você quiser brincar com tópicos em C ++, se você usar,
cout
poderá obter alguns resultados interessantes.Considere este código:
Agora, a saída é toda embaralhada. Também pode gerar resultados diferentes, tente executar várias vezes:
Você pode usar
printf
para acertar ou usarmutex
.Diverta-se!
fonte
thread
s não faz a saída ficar louca. Acabei de reproduzir e encontrei ambosxyz
eABC
na saída. Não houve mutilação b / wABC
asABABAB
.cout
funciona com threads, mas tenho certeza de que o código que você está mostrando não é o que você usou para obter essas saídas. Seu código passa a string"ABC"
para o thread 1 e"xyz"
para o thread 2, mas sua saída mostraAAA
eBBB
. Por favor, corrija, porque agora é confuso.Ambos são usados para imprimir valores. Eles têm uma sintaxe completamente diferente. C ++ possui ambos, C apenas possui printf.
fonte
Eu gostaria de dizer que a falta de extensibilidade não
printf
é inteiramente verdadeira:em C, é verdade. Mas em C, não há classes reais.
Em C ++, é possível sobrecarregar o operador de conversão, sobrecarregando um
char*
operador e usandoprintf
assim:possível, se Foo sobrecarregar o bom operador. Ou se você fez um bom método. Em suma,
printf
é tão extensível quantocout
para mim.Argumento técnico que posso ver para fluxos C ++ (em geral ... não apenas cout.) São:
Segurança tipográfica. (E, a propósito, se eu quiser imprimir uma única que
'\n'
eu usoputchar('\n')
... não usarei uma bomba nuclear para matar um inseto.).Mais simples de aprender. (sem parâmetros "complicados" para aprender, apenas para usar
<<
e>>
operadores)Trabalhar nativamente com
std::string
(poisprintf
existestd::string::c_str()
, mas parascanf
?)Pois
printf
eu vejo:Formatação complexa mais fácil, ou pelo menos mais curta (em termos de caracteres escritos). Muito mais legível para mim (questão de gosto, eu acho).
Melhor controle do que a função fez (Retorne quantos caracteres foram escritos e existe o
%n
formatador: "Nada impresso. O argumento deve ser um ponteiro para um int assinado, onde o número de caracteres gravados até agora é armazenado." ( From printf - Referência C ++ )Melhores possibilidades de depuração. Pela mesma razão que o último argumento.
Minhas preferências pessoais vão para as funções
printf
(escanf
), principalmente porque eu amo linhas curtas e porque não acho que problemas de digitação na impressão de texto sejam realmente difíceis de evitar. A única coisa que eu deploro com funções no estilo C é que issostd::string
não é suportado. Temos que passar por umchar*
antes de darprintf
(com ostd::string::c_str()
se queremos ler, mas como escrever?)fonte
char*
não será usada.char*
vidas e por quanto tempo e os perigos da definição do usuário. elencos implícitos.Mais diferenças: "printf" retorna um valor inteiro (igual ao número de caracteres impressos) e "cout" não retorna nada
E.
cout << "y = " << 7;
não é atômico.printf("%s = %d", "y", 7);
é atômico.cout executa digitação, printf não.
Não há iostream equivalente a
"% d"
fonte
cout
não retorna nada porque é um objeto, não uma função.operator<<
retorna algo (normalmente seu operando esquerdo, mas um valor falso se houver um erro). E em que sentido é oprintf
chamado "atômico"?printf("%s\n",7);
%s
é ?printf
argumento % s deve ter um ponteiro válido para uma sequência terminada nula. O intervalo de memória '7' (um ponteiro) geralmente não é válido; uma falha de segmentação pode ter sorte. Em alguns sistemas, o '7' pode imprimir muito lixo em um console e você precisaria analisá-lo por um dia antes que o programa parasse. Em outras palavras, isso é uma coisa ruimprintf
. As ferramentas de análise estática podem capturar muitos desses problemas.printf
não faz typechecking, eu nunca tenha usado um compilador que não me alertar sobre erros de tipo comprintf
...TL; DR: Sempre faça sua própria pesquisa em relação ao tamanho do código de máquina gerado , desempenho , legibilidade e tempo de codificação antes de confiar em comentários aleatórios on-line, incluindo este.
Eu não sou especialista. Acabei de ouvir dois colegas de trabalho falando sobre como devemos evitar o uso de C ++ em sistemas embarcados devido a problemas de desempenho. Bem, interessante o suficiente, fiz um benchmark com base em uma tarefa real do projeto.
Nessa tarefa, tivemos que escrever algumas configurações na RAM. Algo como:
Aqui estão meus programas de benchmark (Sim, eu sei que o OP perguntou sobre printf (), não fprintf (). Tente capturar a essência e, a propósito, o link do OP aponta para fprintf () de qualquer maneira.)
Programa C:
Programa C ++:
Eu fiz o meu melhor para polir antes de repetir as duas vezes 100.000. Aqui estão os resultados:
Programa C:
Programa C ++:
Tamanho do arquivo de objeto:
Conclusão: Na minha plataforma muito específica , com um processador muito específico , executando uma versão muito específica do kernel do Linux , para executar um programa que é compilado com uma versão muito específica do GCC , para realizar uma tarefa muito específica , eu diria a abordagem C ++ é mais adequada porque é executada significativamente mais rápido e oferece uma legibilidade muito melhor. Por outro lado, C oferece pouca presença, na minha opinião, significa quase nada porque o tamanho do programa não é da nossa preocupação.
Lembre-se, YMMV.
fonte
Não sou programador, mas sou engenheiro de fatores humanos. Eu sinto que uma linguagem de programação deve ser fácil de aprender, entender e usar, e isso exige que ela tenha uma estrutura lingüística simples e consistente. Embora todas as línguas sejam simbólicas e, portanto, em sua essência, arbitrárias, existem convenções e segui-las facilita o aprendizado e o uso da língua.
Há um grande número de funções em C ++ e outras linguagens escritas como função (parâmetro), uma sintaxe que foi originalmente usada para relacionamentos funcionais em matemática na era anterior ao computador.
printf()
segue esta sintaxe e se os escritores do C ++ desejassem criar qualquer método logicamente diferente para ler e gravar arquivos, eles poderiam simplesmente criar uma função diferente usando uma sintaxe semelhante.No Python, é claro que podemos imprimir usando a
object.method
sintaxe também bastante padrão , ou seja, variableename.print, já que variáveis são objetos, mas em C ++ elas não são.Não gosto da sintaxe cout porque o operador << não segue nenhuma regra. É um método ou função, ou seja, pega um parâmetro e faz algo a ele. No entanto, está escrito como se fosse um operador de comparação matemática. Esta é uma péssima abordagem do ponto de vista dos fatores humanos.
fonte
printf
é uma função enquantocout
é uma variável.fonte
printf
é uma função, masprintf()
é uma chamada de função =)