Respostas:
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 com qsort
(2 vezes), em custo do tamanho do executável).
[15.1] Por que devo usar em
<iostream>
vez do tradicional<cstdio>
?Aumente a segurança de tipos, reduza erros, permita extensibilidade e forneça herdabilidade.
printf()
indiscutivelmente não está quebrado escanf()
talvez seja habitável, apesar de propenso a erros, no entanto, ambos são limitados com relação ao que a C / E / S pode fazer. A E / S C ++ (usando<<
e>>
) é relativa a C (usandoprintf()
escanf()
):
- Mais seguro para
<iostream>
o tipo : Com , o tipo de objeto que está sendo E / S é conhecido estaticamente pelo compilador. Por outro lado,<cstdio>
usa os campos "%" para descobrir os tipos dinamicamente.- Menos propenso a erros: com
<iostream>
, não há tokens "%" redundantes que precisam ser consistentes com os objetos reais com E / S. A remoção de redundância remove uma classe de erros.- Extensível: O
<iostream>
mecanismo C ++ permite que novos tipos definidos pelo usuário sejam E / S sem quebrar o código existente. Imagine o caos se todos estivessem simultaneamente adicionando novos campos "%" incompatíveis aprintf()
escanf()
?!- Herdável: O
<iostream>
mecanismo C ++ é criado a partir de classes reais comostd::ostream
estd::istream
. Ao contrário<cstdio>
do que sãoFILE*
, são classes reais e, portanto, herdáveis. Isso significa que você pode ter outras coisas definidas pelo usuário que parecem e agem como fluxos, mas que fazem as coisas estranhas e maravilhosas que você deseja. Você automaticamente usa os zilhões de linhas de código de E / S escritas por usuários que você nem conhece, e eles não precisam saber sobre sua classe "stream estendido".
Por outro lado, printf
é significativamente mais rápido, o que pode justificar usá-lo de preferência cout
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 /)
printf()
também é suposto ser extensível. Veja "printf hooks" em udrepper.livejournal.com/20948.html
printf
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:
cout with only endl 1461.310252 ms
cout with only '\n' 343.080217 ms
printf with only '\n' 90.295948 ms
cout with string constant and endl 1892.975381 ms
cout with string constant and '\n' 416.123446 ms
printf with string constant and '\n' 472.073070 ms
cout with some stuff and endl 3496.489748 ms
cout with some stuff and '\n' 2638.272046 ms
printf with some stuff and '\n' 2520.318314 ms
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 que printf
; 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).
#include <stdio.h>
#include <iostream>
#include <ctime>
class TimedSection {
char const *d_name;
timespec d_start;
public:
TimedSection(char const *name) :
d_name(name)
{
clock_gettime(CLOCK_REALTIME, &d_start);
}
~TimedSection() {
timespec end;
clock_gettime(CLOCK_REALTIME, &end);
double duration = 1e3 * (end.tv_sec - d_start.tv_sec) +
1e-6 * (end.tv_nsec - d_start.tv_nsec);
std::cerr << d_name << '\t' << std::fixed << duration << " ms\n";
}
};
int main() {
const int iters = 10000000;
char const *text = "01234567890123456789";
{
TimedSection s("cout with only endl");
for (int i = 0; i < iters; ++i)
std::cout << std::endl;
}
{
TimedSection s("cout with only '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << '\n';
}
{
TimedSection s("printf with only '\\n'");
for (int i = 0; i < iters; ++i)
printf("\n");
}
{
TimedSection s("cout with string constant and endl");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789" << std::endl;
}
{
TimedSection s("cout with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789\n";
}
{
TimedSection s("printf with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
printf("01234567890123456789\n");
}
{
TimedSection s("cout with some stuff and endl");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << std::endl;
}
{
TimedSection s("cout with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << '\n';
}
{
TimedSection s("printf with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
printf("%s01234567890123456789%i\n", text, i);
}
}
printf()
e std::ostream
é que o primeiro gera todos os argumentos em uma única chamada, ao passo que std::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
ou fprintf
e stringstream
ou fstream
.
E cito :
Em termos de alto nível, as principais diferenças são segurança de tipo (o cstdio não o possui), desempenho (a maioria das implementações do iostreams são mais lentas que as do cstdio) e extensibilidade (o iostreams permite destinos de saída personalizados e saída contínua de tipos definidos pelo usuário).
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.
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 :)
#include <iostream>
#include <fstream>
using namespace std;
int main ()
{
cout << "This is sent to prompt" << endl;
ofstream file;
file.open ("test.txt");
streambuf* sbuf = cout.rdbuf();
cout.rdbuf(file.rdbuf());
cout << "This is sent to file" << endl;
cout.rdbuf(sbuf);
cout << "This is also sent to prompt" << endl;
return 0;
}
3) Acho que o cout é mais legível, principalmente quando temos muitos parâmetros.
Um problemacout
é com as opções de formatação. Formatar os dados (precisão, justificativa etc.) printf
é mais fácil.
printf
para um arquivo, substituindo-o por fprintf
...
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 que printf
. Isso também é verdade string
, 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
(e string
) se já estiver usando o STL. Caso contrário, eu tendem a evitá-lo.
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,
#include <iostream>
#include <cstdlib>
using namespace std;
class Something
{
public:
Something(int x, int y, int z) : a(x), b(y), c(z) { }
int a;
int b;
int c;
friend ostream& operator<<(ostream&, const Something&);
};
ostream& operator<<(ostream& o, const Something& s)
{
o << s.a << ", " << s.b << ", " << s.c;
return o;
}
int main(void)
{
Something s(3, 2, 1);
// output with printf
printf("%i, %i, %i\n", s.a, s.b, s.c);
// output with cout
cout << s << endl;
return 0;
}
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.
Claro que você pode escrever "algo" um pouco melhor para manter a manutenção:
#include <iostream>
#include <cstdlib>
using namespace std;
class Something
{
public:
Something(int x, int y, int z) : a(x), b(y), c(z) { }
int a;
int b;
int c;
friend ostream& operator<<(ostream&, const Something&);
void print() const { printf("%i, %i, %i\n", a, b, c); }
};
ostream& operator<<(ostream& o, const Something& s)
{
o << s.a << ", " << s.b << ", " << s.c;
return o;
}
int main(void)
{
Something s(3, 2, 1);
// Output with printf
s.print(); // Simple as well, isn't it?
// Output with cout
cout << s << endl;
return 0;
}
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):
#include <stdio.h>
#include <iostream>
#include <ctime>
class TimedSection {
char const *d_name;
//timespec d_start;
clock_t d_start;
public:
TimedSection(char const *name) :
d_name(name)
{
//clock_gettime(CLOCK_REALTIME, &d_start);
d_start = clock();
}
~TimedSection() {
clock_t end;
//clock_gettime(CLOCK_REALTIME, &end);
end = clock();
double duration = /*1e3 * (end.tv_sec - d_start.tv_sec) +
1e-6 * (end.tv_nsec - d_start.tv_nsec);
*/
(double) (end - d_start) / CLOCKS_PER_SEC;
std::cerr << d_name << '\t' << std::fixed << duration * 1000.0 << " ms\n";
}
};
int main() {
const int iters = 1000000;
char const *text = "01234567890123456789";
{
TimedSection s("cout with only endl");
for (int i = 0; i < iters; ++i)
std::cout << std::endl;
}
{
TimedSection s("cout with only '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << '\n';
}
{
TimedSection s("printf with only '\\n'");
for (int i = 0; i < iters; ++i)
printf("\n");
}
{
TimedSection s("cout with string constant and endl");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789" << std::endl;
}
{
TimedSection s("cout with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << "01234567890123456789\n";
}
{
TimedSection s("printf with string constant and '\\n'");
for (int i = 0; i < iters; ++i)
printf("01234567890123456789\n");
}
{
TimedSection s("cout with some stuff and endl");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << std::endl;
}
{
TimedSection s("cout with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
std::cout << text << "01234567890123456789" << i << '\n';
}
{
TimedSection s("printf with some stuff and '\\n'");
for (int i = 0; i < iters; ++i)
printf("%s01234567890123456789%i\n", text, i);
}
{
TimedSection s("cout with formatted double (width & precision once)");
std::cout << std::fixed << std::scientific << std::right << std::showpoint;
std::cout.width(8);
for (int i = 0; i < iters; ++i)
std::cout << text << 8.315 << i << '\n';
}
{
TimedSection s("cout with formatted double (width & precision on each call)");
std::cout << std::fixed << std::scientific << std::right << std::showpoint;
for (int i = 0; i < iters; ++i)
{ std::cout.width(8);
std::cout.precision(3);
std::cout << text << 8.315 << i << '\n';
}
}
{
TimedSection s("printf with formatted double");
for (int i = 0; i < iters; ++i)
printf("%8.3f%i\n", 8.315, i);
}
}
O resultado é:
cout with only endl 6453.000000 ms
cout with only '\n' 125.000000 ms
printf with only '\n' 156.000000 ms
cout with string constant and endl 6937.000000 ms
cout with string constant and '\n' 1391.000000 ms
printf with string constant and '\n' 3391.000000 ms
cout with some stuff and endl 9672.000000 ms
cout with some stuff and '\n' 7296.000000 ms
printf with some stuff and '\n' 12235.000000 ms
cout with formatted double (width & precision once) 7906.000000 ms
cout with formatted double (width & precision on each call) 9141.000000 ms
printf with formatted double 3312.000000 ms
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:
#include <string>
#include <iostream>
#include <thread>
using namespace std;
void task(int taskNum, string msg) {
for (int i = 0; i < 5; ++i) {
cout << "#" << taskNum << ": " << msg << endl;
}
}
int main() {
thread t1(task, 1, "AAA");
thread t2(task, 2, "BBB");
t1.join();
t2.join();
return 0;
}
// g++ ./thread.cpp -o thread.out -ansi -pedantic -pthread -std=c++0x
Agora, a saída é toda embaralhada. Também pode gerar resultados diferentes, tente executar várias vezes:
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
Você pode usar printf
para acertar ou usar mutex
.
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
Diverta-se!
thread
s não faz a saída ficar louca. Acabei de reproduzir e encontrei ambos xyz
e ABC
na saída. Não houve mutilação b / w ABC
as ABABAB
.
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 mostra AAA
e BBB
. Por favor, corrija, porque agora é confuso.
cout<< "Hello";
printf("%s", "Hello");
Ambos são usados para imprimir valores. Eles têm uma sintaxe completamente diferente. C ++ possui ambos, C apenas possui printf.
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 usando printf
assim:
Foo bar;
...;
printf("%s",bar);
possível, se Foo sobrecarregar o bom operador. Ou se você fez um bom método. Em suma, printf
é tão extensível quanto cout
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 uso putchar('\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
(pois printf
existe std::string::c_str()
, mas para scanf
?)
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
(e scanf
), 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 isso std::string
não é suportado. Temos que passar por um char*
antes de dar printf
(com o std::string::c_str()
se queremos ler, mas como escrever?)
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"
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 é o printf
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 ruim printf
. 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 com printf
...
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:
café =
açúcar quente = nenhum
leite = peito
mac = AA: BB: CC: DD: EE: FF
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:
char coffee[10], sugar[10], milk[10];
unsigned char mac[6];
/* Initialize those things here. */
FILE * f = fopen("a.txt", "wt");
fprintf(f, "coffee=%s\nsugar=%s\nmilk=%s\nmac=%02X:%02X:%02X:%02X:%02X:%02X\n", coffee, sugar, milk, mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]);
fclose(f);
Programa C ++:
//Everything else is identical except:
std::ofstream f("a.txt", std::ios::out);
f << "coffee=" << coffee << "\n";
f << "sugar=" << sugar << "\n";
f << "milk=" << milk << "\n";
f << "mac=" << (int)mac[0] << ":"
<< (int)mac[1] << ":"
<< (int)mac[2] << ":"
<< (int)mac[3] << ":"
<< (int)mac[4] << ":"
<< (int)mac[5] << endl;
f.close();
Eu fiz o meu melhor para polir antes de repetir as duas vezes 100.000. Aqui estão os resultados:
Programa C:
real 0m 8.01s
user 0m 2.37s
sys 0m 5.58s
Programa C ++:
real 0m 6.07s
user 0m 3.18s
sys 0m 2.84s
Tamanho do arquivo de objeto:
C - 2,092 bytes
C++ - 3,272 bytes
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.
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.
printf
é uma função enquanto cout
é uma variável.
printf
é uma função, mas printf()
é uma chamada de função =)