Meu entendimento é que string
é um membro do std
espaço para nome, então por que ocorre o seguinte?
#include <iostream>
int main()
{
using namespace std;
string myString = "Press ENTER to quit program!";
cout << "Come up and C++ me some time." << endl;
printf("Follow this command: %s", myString);
cin.get();
return 0;
}
Cada vez que o programa é executado, myString
imprime uma seqüência aparentemente aleatória de 3 caracteres, como na saída acima.
Respostas:
Ele está compilando porque
printf
não é seguro para o tipo, pois usa argumentos variáveis no sentido C 1 .printf
não tem opção parastd::string
, apenas uma string no estilo C. Usar outra coisa no lugar do que ele espera definitivamente não lhe dará os resultados desejados. Na verdade, é um comportamento indefinido, para que tudo possa acontecer.A maneira mais fácil de corrigir isso, já que você está usando C ++, é imprimindo normalmente com
std::cout
, uma vezstd::string
que suporta isso através da sobrecarga do operador:Se, por algum motivo, você precisar extrair a seqüência de caracteres no estilo C, poderá usar o
c_str()
método destd::string
para obter umaconst char *
terminação nula. Usando seu exemplo:Se você deseja uma função semelhante
printf
, mas com segurança, procure modelos variados (C ++ 11, suportado em todos os principais compiladores a partir do MSVC12). Você pode encontrar um exemplo de um aqui . Não há nada que eu saiba sobre isso implementado na biblioteca padrão, mas pode haver no Boost, especificamenteboost::format
.[1]: Isso significa que você pode transmitir qualquer número de argumentos, mas a função depende de você para informar o número e os tipos desses argumentos. No caso de
printf
, isso significa uma string com informações de tipo codificado, como%d
significadoint
. Se você mentir sobre o tipo ou número, a função não possui um meio padrão de saber, embora alguns compiladores tenham a capacidade de verificar e emitir avisos quando você mente.fonte
Por favor não use
printf("%s", your_string.c_str());
Use em
cout << your_string;
vez disso. Curto, simples e seguro. De fato, quando você está escrevendo C ++, geralmente deseja evitarprintf
completamente - é uma sobra de C que raramente é necessária ou útil em C ++.Por que você deve usar em
cout
vez deprintf
, os motivos são numerosos. Aqui está uma amostra de alguns dos mais óbvios:printf
não é seguro para o tipo. Se o tipo que você passar for diferente daquele fornecido no especificador de conversão,printf
tentará usar o que encontrar na pilha como se fosse o tipo especificado, fornecendo um comportamento indefinido. Alguns compiladores podem alertar sobre isso em algumas circunstâncias, mas alguns não podem / não querem, e nenhum pode em todas as circunstâncias.printf
não é extensível. Você só pode passar tipos primitivos para ele. O conjunto de especificadores de conversão que ele entende é codificado em sua implementação e não há como adicionar mais / outros. A maioria dos C ++ bem escritos deve usar esses tipos principalmente para implementar tipos orientados para o problema que está sendo resolvido.Torna a formatação decente muito mais difícil. Para um exemplo óbvio, quando você está imprimindo números para as pessoas lerem, normalmente deseja inserir milhares de separadores a cada poucos dígitos. O número exato de dígitos e os caracteres usados como separadores variam, mas
cout
isso também abrange. Por exemplo:O código de idioma sem nome (o "") escolhe um código de idioma com base na configuração do usuário. Portanto, na minha máquina (configurada para inglês dos EUA) isso é impresso como
123,456.78
. Para alguém que tem seu computador configurado para (digamos) a Alemanha, ele imprimirá algo como123.456,78
. Para alguém com ele configurado para a Índia, seria impresso como1,23,456.78
(e é claro que existem muitos outros). Comprintf
Recebo exatamente um resultado:123456.78
. É consistente, mas é constantemente errado para todos em todos os lugares. Essencialmente, a única maneira de contornar isso é fazer a formatação separadamente e passar o resultado como uma string paraprintf
, porqueprintf
ela simplesmente não fará o trabalho corretamente.printf
seqüências de formato podem ser ilegíveis. Mesmo entre os programadores C que usamprintf
praticamente todos os dias, eu acho que pelo menos 99% precisariam procurar coisas para ter certeza do que significa o#
in%#x
e como isso difere do que o#
in%#f
significa (e sim, eles significam coisas totalmente diferentes )fonte
#include <string>
. O VC ++ possui algumas peculiaridades em seus cabeçalhos que permitem definir uma sequência, mas não a enviacout
, sem incluir o<string>
cabeçalho.cout
é mais lento, é porque você usoustd::endl
onde não deveria.use
myString.c_str()
se você deseja que uma string do tipo c (const char*
) use com printfobrigado
fonte
Use std :: printf e c_str () exemplo:
fonte
O principal motivo é provavelmente que uma string C ++ é uma estrutura que inclui um valor de tamanho atual, não apenas o endereço de uma sequência de caracteres terminada por um byte 0. Printf e seus parentes esperam encontrar essa sequência, não uma estrutura, e, portanto, ficam confusos com as seqüências de caracteres C ++.
Falando por mim, acredito que printf tem um local que não pode ser facilmente preenchido por recursos sintáticos do C ++, assim como as estruturas de tabela em html têm um local que não pode ser facilmente preenchido por divs. Como Dykstra escreveu mais tarde sobre o goto, ele não pretendia iniciar uma religião e estava apenas argumentando contra usá-la como argumento para compensar códigos mal projetados.
Seria muito bom se o projeto GNU adicionasse a família printf às suas extensões g ++.
fonte
Printf é realmente muito bom de usar se o tamanho importa. Ou seja, se você estiver executando um programa em que a memória é um problema, o printf é na verdade uma solução muito boa e insuficiente. Cout essencialmente desloca bits para dar espaço para a string, enquanto printf apenas pega algum tipo de parâmetro e o imprime na tela. Se você compilasse um programa hello world simples, o printf seria capaz de compilá-lo em menos de 60.000 bits em vez de cout, levaria mais de 1 milhão de bits para compilar.
Para sua situação, eu sugiro usar o cout simplesmente porque é muito mais conveniente de usar. Embora, eu diria que printf é algo bom de se saber.
fonte
printf
aceita um número variável de argumentos. Esses podem ter apenas tipos de dados antigos simples (POD). Código que transmite qualquer coisa que não seja POD paraprintf
compilar apenas porque o compilador supõe que você tenha o formato correto.%s
significa que o argumento respectivo deve ser um ponteiro para achar
. No seu caso, é umstd::string
nãoconst char*
.printf
não sabe porque o tipo de argumento se perde e deve ser restaurado a partir do parâmetro format Ao transformar essestd::string
argumento emconst char*
ponteiro resultante, ele apontará para alguma região irrelevante da memória, em vez da string C desejada. Por esse motivo, seu código imprime sem sentido.Embora
printf
seja uma excelente opção para imprimir texto formatado (especialmente se você pretende ter preenchimento), pode ser perigoso se você não tiver ativado os avisos do compilador. Sempre ative avisos, pois erros como esse são facilmente evitáveis. Não há razão para usar ostd::cout
mecanismo desajeitado se aprintf
família puder executar a mesma tarefa de uma maneira muito mais rápida e bonita. Apenas certifique-se de ter ativado todos os avisos (-Wall -Wextra
) e você será bom. Caso você use sua própriaprintf
implementação personalizada , declare-a com o__attribute__
mecanismo que permite ao compilador verificar a cadeia de formatação em relação aos parâmetros fornecidos .fonte