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 printfC (no entanto, você pode usá-lo em C ++, assim como quase qualquer outra coisa em C). Agora, vou ser sincero aqui; ambos printfe std::couttê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::coutdepende 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::ostreamo 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 printfe std::coutusam sintaxe diferente. printfusa 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 printfformatos são complexos demais para serem utilizáveis sem eles. No entanto, std::coutusa 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::endlna 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::coutmistura do estado e dos valores reais. Eu nunca vi uma linguagem em que algo std::setfilldesse tipo fosse um tipo (além de C ++, é claro). printfsepara claramente argumentos e tipo real. Eu realmente preferiria manter a printfversão dele (mesmo que pareça meio enigmática) em comparação com a iostreamversã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 printfmentiras. A printfstring 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 iostreamquais construções printfvocê 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::coutlida com todos os tipos para você, enquanto printfrequer 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_cmétodo de std::string)). Por exemplo, para imprimir size_t, você precisa usar %zd, enquanto int64_texigirá 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 .
\0Como printfusa 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 %ccom'\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 stdiopode 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 printfou iostream. Eu acho que printf poderia ser mais rápido desde uma rápida olhada no assembly (compilado com clang usando a -O3opção do compilador). Assumindo o meu exemplo de erro, o printfexemplo faz muito menos chamadas que o coutexemplo. Isto é int maincom 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 printfargumentos. É sobre isso; Não há mais nada. Para comparação, isso é iostreamcompilado 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 printfformatos 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 printfem certos casos) - as constantes que terminam com \ngeralmente 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 printfsequê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::ostreamestd::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 coutem 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
printfnã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 iostreams 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 -lrttempo).
#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::ostreamgera 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.
printfpode 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.
sprintfou fprintfe stringstreamou 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.
printfpara um arquivo, substituindo-o por fprintf...
Dois pontos não mencionados aqui que considero significativos:
1) coutcarrega 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) coutusa <<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
endltão menos eficiente que '\n'?
endllibera o buffer, e \nnã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, coutpoderá 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 printfpara 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!
threads não faz a saída ficar louca. Acabei de reproduzir e encontrei ambos xyze ABCna saída. Não houve mutilação b / w ABCas ABABAB.
coutfunciona 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 AAAe 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 printfassim:
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 coutpara 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 printfexiste std::string::c_str(), mas para scanf?)
Pois printfeu 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 %nformatador: "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::stringnã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"
coutnã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 printfchamado "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.
printfnã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.methodsintaxe 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 =)