Tenho uma função que aceita uma string, que é:
void log_out(char *);
Ao chamá-lo, preciso criar uma string formatada em tempo real, como:
int i = 1;
log_out("some text %d", i);
Como faço isso em ANSI C?
Apenas, uma vez que sprintf()
retorna um int, isso significa que tenho que escrever pelo menos 3 comandos, como:
char *s;
sprintf(s, "%d\t%d", ix, iy);
log_out(s);
Alguma maneira de encurtar isso?
Respostas:
Use sprintf .
Parâmetros:
Exemplo:
fonte
Se você tem um sistema compatível com POSIX-2008 (qualquer Linux moderno), você pode usar a
asprintf()
função segura e conveniente : Ele terámalloc()
memória suficiente para você, você não precisa se preocupar com o tamanho máximo da string. Use-o assim:Este é o esforço mínimo que você pode fazer para construir a corda de maneira segura. O
sprintf()
código que você forneceu na pergunta é profundamente falho:Não há memória alocada por trás do ponteiro. Você está escrevendo a string em um local aleatório na memória!
Mesmo se você tivesse escrito
você estaria em apuros, porque não sabe qual número colocar entre colchetes.
Mesmo se você tivesse usado a variante "segura"
snprintf()
, ainda correria o perigo de suas strings ficarem truncadas. Ao gravar em um arquivo de log, essa é uma preocupação relativamente menor, mas tem o potencial de cortar precisamente as informações que seriam úteis. Além disso, ele cortará o caractere final da linha final, colando a próxima linha de log ao final da linha escrita sem sucesso.Se você tentar usar uma combinação de
malloc()
esnprintf()
para produzir um comportamento correto em todos os casos, acabará com quase o dobro do código que eu forneciasprintf()
e basicamente reprogramará a funcionalidade deasprintf()
.Se você deseja fornecer um wrapper de
log_out()
que pode receber umaprintf()
lista de parâmetros de estilo, você pode usar a variantevasprintf()
que recebe ava_list
como argumento. Aqui está uma implementação perfeitamente segura de tal wrapper:fonte
asprintf()
não faz parte do padrão C 2011 nem do POSIX, nem mesmo do POSIX 2008 ou 2013. Faz parte do TR 27431-2: consulte Você usa as funções 'seguras' do TR 24731?Parece-me que você deseja passar facilmente uma string criada usando a formatação no estilo printf para a função que você já possui que usa uma string simples. Você pode criar uma função de wrapper usando
stdarg.h
recursos evsnprintf()
(que podem não estar prontamente disponíveis, dependendo do seu compilador / plataforma):Para plataformas que não fornecem uma boa implementação (ou qualquer implementação) da
snprintf()
família de rotinas, usei com sucesso um domínio quase públicosnprintf()
de Holger Weiss .fonte
Se você tiver o código
log_out()
, reescreva-o. Provavelmente, você pode fazer:Se houver necessidade de informações de registro extras, elas podem ser impressas antes ou depois da mensagem exibida. Isso economiza alocação de memória e tamanhos de buffer duvidosos e assim por diante. Você provavelmente precisa inicializar
logfp
para zero (ponteiro nulo) e verificar se ele é nulo e abrir o arquivo de log conforme apropriado - mas o código existentelog_out()
deve lidar com isso de qualquer maneira.A vantagem dessa solução é que você pode simplesmente chamá-la como se fosse uma variante de
printf()
; na verdade, é uma variante menor emprintf()
.Se você não tem o código
log_out()
, considere se você pode substituí-lo por uma variante como a descrita acima. Se você pode usar o mesmo nome, dependerá de sua estrutura de aplicativo e da fonte final dalog_out()
função atual . Se estiver no mesmo arquivo de objeto que outra função indispensável, você terá que usar um novo nome. Se você não conseguir descobrir como replicá-lo exatamente, terá que usar alguma variante, como as fornecidas em outras respostas, que aloca uma quantidade adequada de memória.Obviamente, você agora chama o em
log_out_wrapper()
vez delog_out()
- mas a alocação de memória e assim por diante é feita uma vez. Eu me reservo o direito de superalocar espaço em um byte desnecessário - não verifiquei duas vezes se o comprimento retornado porvsnprintf()
inclui o nulo de terminação ou não.fonte
Não use sprintf.
Isso irá estourar seu String-Buffer e travar seu Programa.
Sempre use snprintf
fonte
Eu não fiz isso, então vou apenas apontar para a resposta certa.
C tem disposições para funções que usam números não especificados de operandos, usando o
<stdarg.h>
cabeçalho. Você pode definir sua função comovoid log_out(const char *fmt, ...);
e obter ova_list
interior da função. Em seguida, você pode alocar memória e chamarvsprintf()
com a memória alocada, formato eva_list
.Como alternativa, você poderia usar isso para escrever uma função análoga a
sprintf()
que alocaria memória e retornaria a string formatada, gerando-a mais ou menos como acima. Seria um vazamento de memória, mas se você estiver apenas desconectando, pode não importar.fonte
http://www.gnu.org/software/hello/manual/libc/Variable-Arguments-Output.html fornece o seguinte exemplo para imprimir em stderr. Você pode modificá-lo para usar sua função de registro:
Em vez de vfprintf, você precisará usar o vsprintf onde precisa fornecer um buffer adequado para imprimir.
fonte