Pergunta

No novo código C ++, que tendem a usar a ++ biblioteca iostream C em vez da biblioteca C stdio.

Tenho notado alguns programadores parecem furar a stdio, insistindo que é mais portátil.

É este realmente o caso? O que é melhor usar?

Foi útil?

Solução

Para responder à pergunta original:
Qualquer coisa que pode ser feito usando stdio pode ser feito usando a biblioteca iostream.

Disadvantages of iostreams: verbose
Advantages    of iostreams: easy to extend for new non POD types.

O passo para a frente a C ++ feita ao longo C foi de segurança tipo.

  • iostreams foi projetado para ser digitar explicitamente seguro. Assim, a atribuição a um objeto verificado explicitamente o tipo (no momento do compilador) do objeto a ser atribuído também (gerando um erro tempo de compilação, se necessário). Assim, evitar de tempo de execução de memória sobre-corre ou escrever um valor flutuante para um objeto de carvão etc.

  • scanf () / printf () e família, por outro lado contar com o programador obter a seqüência de formato correto e não houve verificação de tipo (eu acredito gcc tem uma extensão que ajuda). Como resultado, foi a fonte de muitos erros (como programadores são menos perfeitos em sua análise do que compiladores [não vai dizer compiladores são perfeitos apenas melhor do que os seres humanos]).

Só para esclarecer comentários de Colin Jensen.

  • As bibliotecas iostream ter sido estável desde a divulgação do último padrão (I esquecer o ano real, mas cerca de 10 anos atrás).

Para esclarecer comentários por Mikael Jansson.

  • As outras línguas que ele menciona que o uso do estilo de formato tem garantias explícitas para evitar os efeitos colaterais perigosos da C stdio biblioteca que pode (em C, mas não as línguas mencionadas) causa um acidente de tempo de execução.

NB. Eu concordo que a biblioteca iostream é um pouco sobre o lado detalhado. Mas eu estou disposto a colocar-se com o verboseness para garantir a segurança de tempo de execução. Mas podemos reduzir a verbosidade usando Format impulso Biblioteca .

#include <iostream>
#include <iomanip>
#include <boost/format.hpp>

struct X
{  // this structure reverse engineered from
   // example provided by 'Mikael Jansson' in order to make this a running example

    char*       name;
    double      mean;
    int         sample_count;
};
int main()
{
    X   stats[] = {{"Plop",5.6,2}};

    // nonsense output, just to exemplify

    // stdio version
    fprintf(stderr, "at %p/%s: mean value %.3f of %4d samples\n",
            stats, stats->name, stats->mean, stats->sample_count);

    // iostream
    std::cerr << "at " << (void*)stats << "/" << stats->name
              << ": mean value " << std::fixed << std::setprecision(3) << stats->mean
              << " of " << std::setw(4) << std::setfill(' ') << stats->sample_count
              << " samples\n";

    // iostream with boost::format
    std::cerr << boost::format("at %p/%s: mean value %.3f of %4d samples\n")
                % stats % stats->name % stats->mean % stats->sample_count;
}

Outras dicas

É muito detalhado.

Ponder a construção iostream para fazer o seguinte (semelhante para scanf):

// nonsense output, just to examplify
fprintf(stderr, "at %p/%s: mean value %.3f of %4d samples\n",
    stats, stats->name, stats->mean, stats->sample_count);

Isso requer algo como:

std::cerr << "at " << static_cast<void*>(stats) << "/" << stats->name
          << ": mean value " << std::precision(3) << stats->mean
          << " of " << std::width(4) << std::fill(' ') << stats->sample_count
          << " samples " << std::endl;

string de formatação é um caso em que objeto-orientedness pode, e deve ser, evitou em favor de uma DSL formatação incorporado em cordas. Considere format do Lisp, de estilo printf do Python formatação, ou PHP, Bash, Perl, Ruby e sua intrapolation string.

iostream para esse caso de uso é equivocada, na melhor das hipóteses.

O impulso Format biblioteca fornece uma alternativa de tipo seguro, orientado a objetos para a corda de estilo printf formatação e é um complemento para iostreams que não sofrem com os problemas habituais de verbosidade devido ao uso inteligente do operador%. Eu recomendo considerando-o usando plain C printf Se você não gosta de formatar com o operador de iostream <<.

De volta aos maus velhos tempos, o comitê de padrões ++ C mantido mucking com a língua e iostreams era um alvo em movimento. Se você usou iostreams, você foi então dada a oportunidade de reescrever partes do seu código de cada ano ou assim. Devido a isso, eu sempre usei stdio que não mudou significativamente desde 1989.

Se eu estivesse fazendo coisas hoje, eu usaria iostreams.

Se, como eu, você aprendeu C antes de aprender C ++, as bibliotecas stdio parecer mais natural para usar. Há prós e contras para iostream vs. stdio mas eu printf miss () ao usar iostream.

Em princípio eu usaria iostreams, na prática, eu faço decimais demasiado formatados, etc que fazem iostreams muito ilegível, então eu uso stdio. Boost :: formato é uma melhoria, mas não muito motivar o suficiente para mim. Na prática, stdio é typesafe quase desde a maioria dos compiladores modernos fazem argumento verificação de qualquer maneira.

É uma área onde eu ainda não estou totalmente feliz com qualquer uma das soluções.

Para IO binário, que tendem a fread e fwrite uso de stdio. Para o material formatado I normalmente vai usar IO Fluxo embora, como Mikael disse, não-trival (não-padrão?) Formatação pode ser um PITA.

Eu vou ser comparando as duas bibliotecas principais do C ++ biblioteca padrão.

Você não deve usar de processamento de corda-rotinas baseadas em C-style-format-string em C ++.

Várias razões existem para mit seu uso:

  • Não typesafe
  • Você não pode passar tipos não-Pod to listas de argumentos variádicos (ou seja, nem a scanf + co., Nem para printf + co.), ou você entra no Stronghold Dark of comportamento indefinido
  • fácil de errar:
    • Você deve gerenciar para manter a cadeia de formato e do "argumento-lista de valores" em sincronia
    • Você deve manter em sincronia corretamente

erros sutis introduzidas em locais remotos

Não é só o printf em si, que não é bom. Software envelhece e é reformulado e modificado, e erros podem ser introduzidos a partir de locais remotos. Suponha que você tenha

.

// foo.h
...
float foo;
...

e em algum lugar ...

// bar/frob/42/icetea.cpp
...
scanf ("%f", &foo);
...

E três anos mais tarde você achar que foo deve ser de algum tipo personalizado ...

// foo.h
...
FixedPoint foo;
...

mas em algum lugar ...

// bar/frob/42/icetea.cpp
...
scanf ("%f", &foo);
...

... então seu velho printf / scanf ainda vai compilar, exceto que agora você pode obter segfaults aleatórios e você não se lembra porquê.

Verbosity de iostreams

Se você acha que printf () é menos detalhado, então há uma certa probabilidade de que você não use força total do seu iostream. Exemplo:

  printf ("My Matrix: %f %f %f %f\n"
          "           %f %f %f %f\n"
          "           %f %f %f %f\n"
          "           %f %f %f %f\n",
          mat(0,0), mat(0,1), mat(0,2), mat(0,3), 
          mat(1,0), mat(1,1), mat(1,2), mat(1,3), 
          mat(2,0), mat(2,1), mat(2,2), mat(2,3), 
          mat(3,0), mat(3,1), mat(3,2), mat(3,3));

Compare isso com utilizando iostreams direita:

cout << mat << '\n';

Você tem que definir uma sobrecarga adequada para o operador <<, que tem mais ou menos a estrutura do printf-coisinha, mas a diferença significativa é que agora você tem algo reutilizáveis ??e typesafe; é claro que você também pode fazer algo re-utilizáveis ??para printf-gostos, mas então você tem printf novamente (e se você substituir os membros da matriz com o novo FixedPoint?), além de outros não-trivialidades, por exemplo, você deve passar FILE * alças ao redor.

formato cordas de estilo C não são melhores para I18N do que iostreams

Note que o formato-cordas são muitas vezes pensou em ser o resgate com a internacionalização, mas eles não são de todo melhor do que iostream a esse respeito:

printf ("Guten Morgen, Sie sind %f Meter groß und haben %d Kinder", 
        someFloat, someInt);

printf ("Good morning, you have %d children and your height is %f meters",
        someFloat, someInt); // Note: Position changed.

// ^^ not the best example, but different languages have generally different
//    order of "variables"

i., Cordas velhas estilo C formato falta de informação posicional tanto quanto iostreams fazer.

Você pode querer considerar boost :: formato , que oferece suporte para afirmar a posição na string de formato explicitamente. De sua seção de exemplos:

cout << format("%1% %2% %3% %2% %1% \n") % "11" % "22" % "333"; // 'simple' style.

Alguns printf-implementações fornecem argumentos posicionais, mas eles são não-padrão.

Devo não formato cordas uso de estilo C?

Além de desempenho (como apontado por Jan Hudec), eu não vejo uma razão. Mas lembre-se:

“Devemos esquecer sobre pequenas eficiências, digamos cerca de 97% do tempo: otimização prematura é a raiz de todo o mal. No entanto, não devemos deixar passar as oportunidades em que críticos 3%. Um bom programador não vai ser embalado em complacência por tal raciocínio, ele vai ser sábio para olhar atentamente para o código crítico; mas só depois que o código foi identificado”- Knuth

e

“Gargalos ocorrem em lugares surpreendentes, por isso, não tente adivinhar e colocar em um hack de velocidade até que você tenha provado que é onde o gargalo é.” - Pike

Sim, printf-implementações são geralmente mais rápido do que iostreams são geralmente mais rápido do que boost :: formato (de uma pequena e específica de referência que eu escrevi, mas em grande parte deve depender da situação em particular: se printf = 100%, então iostream = 160%, e impulso :: formato = 220%)

Mas fazer pensar não cegamente omitir nisso: Quanto tempo você realmente gastar em texto de processamento? Quanto tempo demora o seu programa executado antes de sair? É relevante em tudo para cair de volta para seqüências de formato de estilo C, tipo soltosegurança, diminuição refactorbility, aumentar a probabilidade de erros muito sutis que podem esconder-se durante anos e só podem revelar-se bem em seu rosto favoritos clientes?

Pessoalmente, eu não iria cair para trás se eu não pode ganhar mais de 20% speedup. Mas porque minhas aplicações passar praticamente todo o seu tempo em outras tarefas do que cadeia de processamento, eu nunca tinha que fazer. alguns analisadores Eu escrevi passar praticamente todo o seu tempo no processamento de strings, mas o seu tempo de execução total é tão pequeno que não vale a pena o esforço de teste e verificação.

Alguns enigmas

Finalmente, eu gostaria de memorizar alguns enigmas:

Encontre todos os erros, porque o compilador não vai (ele só pode sugerir se ele é legal):

shared_ptr<float> f(new float);
fscanf (stdout, "%u %s %f", f)

Se nada mais, o que há de errado com esta?

const char *output = "in total, the thing is 50%"
                     "feature  complete";
printf (output);

Embora haja uma série de benefícios para o C ++ iostreams API, um problema significativo é tem é de cerca de i18n. O problema é que a ordem de substituições dos parâmetros podem variar com base na cultura. O exemplo clássico é algo como:

// i18n UNSAFE 
std::cout << "Dear " << name.given << ' ' << name.family << std::endl;

Enquanto que funciona para Inglês, em chinês o nome de família é vem em primeiro lugar.

Quando se trata de traduzir o código para mercados estrangeiros, traduzir trechos é cheio de perigo tão novas l10ns pode exigir alterações no código e não apenas diferentes strings.

boost :: formato parece combinar o melhor de stdio (uma única seqüência formato que pode usar os parâmetros em uma ordem diferente, então eles aparecem) e iostreams (tipo-segurança, extensibilidade).

Eu uso iostreams, principalmente porque isso faz com que seja mais fácil de mexer com o fluxo mais tarde (se eu precisar dele). Por exemplo, você pode descobrir que você deseja exibir a saída em alguma janela traço - isso é relativamente fácil de fazer com cout e cerr. Você pode, claro, mexer com canos e outras coisas em UNIX, mas isso não é tão portátil.

Eu faço amor printf-como formatação, então eu geralmente formatar uma string primeiro, e depois enviá-lo para o buffer. Com o Qt, costumo usar QString :: sprintf (embora eles recomendam usando < a href = "http://doc.trolltech.com/4.4/qstring.html#arg-10" rel = "nofollow noreferrer"> QString :: arg vez). Eu olhei boost.format bem, mas não poderia realmente se acostumar com a sintaxe (demasiados% 's). Eu realmente deveria dar-lhe um olhar, no entanto.

O que eu perca sobre os iolibraries é a entrada formatada.

iostreams não tem uma boa maneira de scanf replicate () e até mesmo impulso não tem a extensão necessária para a entrada.

stdio é melhor para leitura de arquivos binários (como freading blocos em um vector e usando .Resize () etc.). Veja a função read_rest em file.hh em http://nuwen.net/libnuwen.html para um exemplo.

streams C ++ pode engasgar com lotes de bytes ao ler arquivos binários causando uma falsa eof.

Desde iostreams tornaram-se um padrão que você deve usá-los sabendo que seu código irá funcionar com certeza com versões mais recentes do compilador. Eu acho que hoje em dia a maioria dos compiladores sabem muito bem sobre iostreams e não deve haver nenhum problema de usá-los.

Mas se você quiser ficar com funções * printf não pode haver nenhum problema em minha opinião.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top