Ir ao conteúdo
  • Cadastre-se

C Função para gravar dados formatados em uma string


Ir à solução Resolvido por arfneto,

Posts recomendados

Boa noite, colegas.

 

Fiz uma função para gravar dados formatados em uma string com base na função vsnprintf(), a usarei futuramente como parte de outra função. O problema é que quando executo o código no CodeBlocks o retorno é NULL, e no Visual Studio, tudo ocorre bem.

O código é esse:

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

char* dadosf(const char* format, ...);

int main()
{
    printf("<%s>\n", dadosf("Essa string tem 120 caracteres desconsiderando o caractere nulo........................................................."));

    return 0;
}

char* dadosf(const char* format, ...)
{
    int aloc = 101;
    int res = 0;
    char* dados = (char*)malloc(aloc);
    va_list args;

    va_start(args, format);

    if((res = vsnprintf(dados, aloc, format, args)) >= aloc && res >= 0){
        aloc = res + 1;
        dados = (char*)realloc(dados, aloc);
        res = vsnprintf(dados, aloc, format, args);
    }

    va_end(args);

    if(res < 0){
        dados = NULL;
    }

    return dados;
}

 

Vejam os prints que tirei das janelas quando rodei nos IDE.

CodeBlocks:

image.png.0556ac290df612a8621bf129766b733f.png

Visual Studio:

image.png.3c3d7e374645b9acf70dfbb2fc41c6a1.png

 

Alguém teria alguma ideia do motivo?

Obrigado desde já.

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

@LNW Eu substituí o laço da função por um if porque era desnecessário, embora funcionasse também. Se recarregar a página, poderá ver o código editado.

 

O que está na função é o seguinte:

1 hora atrás, Lucca Rodrigues disse:


if((res = vsnprintf(dados, aloc, format, args)) >= aloc && res >= 0){
    aloc = res + 1;
    dados = (char*)realloc(dados, aloc);
    res = vsnprintf(dados, aloc, format, args);
}

Segundo a documentação:

Citação

The vsnprintf function returns the number of characters that are written, not counting the terminating null character.

Eu não tenho como saber quantos caracteres devem ser gravados, então eu chamo realloc() caso a memória alocada anteriormente não seja suficiente, ou seja, caso res >= aloc.

Eu também verifico se res >= 0, porque se for < 0, segundo a documentação:

Citação

A return value of -1 indicates that an encoding error has occurred.

Link para o comentário
Compartilhar em outros sites

  • Solução

Olá!

 

Não sei se entendi seu programa ou o seu problema em si. Com os compiladores que tenho aqui sempre mostra a mesma string, mas não entendi o valor de escrever tantos pontinhos. Vou deixar um exemplo mais abaixo.
 

Code::Blocks ou qualquer outro IDE não va fazer qualquer diferença já que eles não compilam nada. Atente para o compilador que está usando no momento no IDE e para as opções de compilação. Em especial se está usando Release ou Debug mode e as opções de otimização. -O.

  • um programa pode não rodar em Release mode porque tem em Debug o IDE zera certas partes da memória e aí ele roda. Triste, porque depois que está considerado pronto o cara compila sem debug e tudo otimizado e instala e aí não funciona mais :) já vi programas ficarem em produção com o códgio de debug por meses porque ninguém conseguia achar o erro e os prazos já tinham acabado e o programa já tinha sido pago...
  • um programa pode não rodar devido a alguma otimização que acabou entendendo errado o código

Não acho que seja o seu caso em um programa tão simples.

 

Mas por outro lado essa linha

 

    if (res < 0) {
        dados = NULL;
    }

    return dados;

 

que no popular podia ser só
 

	if ( res < 0 ) return NULL;
	return dados;

 

seria uma boa explicação para o seu caso no Code::Blocks. :D Provavelmente deu erro na chamada e só.

 

Olhando mais pra cima no seu código

 

    if ((res = vsnprintf(dados, aloc, format, args)) >= aloc && res >= 0) {
        aloc = res + 1;
        dados = (char*)realloc(dados, aloc);
        res = vsnprintf(dados, aloc, format, args);
    }

 

Se a primeira chamada deu erro res  vai ser negativo e vai retornar NULL para o printf(). Só isso. Porque não faz o simples e chama perror() para saber o que houve?

 

Se está escrevendo dadosf() justamente para testar vsnprintf() pode fazer o programa responder suas perguntas antes...

 

Considere por exemplo

 

char* dadosf(const char* format, ...)
{
    size_t aloc = strlen(format) - 10; // pra nao caber mesmo
    char* dados = (char*)malloc(aloc);
    va_list args;

    va_start(args, format);

    int need = vsnprintf(dados, aloc, format, args);
    printf("Primeira chamada retornou %d\n", need);
    if (need < 0)
    {
        perror("Erro na 1a chamada");
        return NULL;
    };

    if (need > aloc - 1)    // nao cabe, vai truncar
    {
        printf("Necessarios %d, alocados %d. Realocando...\n", need, aloc);
        aloc = 1 + need; // ok, tanto quanto precisa + o zero
        char* p = realloc(dados, aloc);
        if (p == NULL)
        {
            perror("realloc falhou");
            return NULL;
        }
        printf("Alocados %d. Tentando de novo...\n", aloc);
        dados = p;
        need = vsnprintf(dados, aloc, format, args);
    }

    if (need < 0)
    {
        perror("Erro na 2a chamada");
        return NULL;
    };

    va_end(args);
    return dados;
}

 

 

    size_t aloc = strlen(format) - 10; // pra nao caber mesmo
    char* dados = (char*)malloc(aloc);

 

Já garante que não vai caber
 

    int need = vsnprintf(dados, aloc, format, args);
    printf("Primeira chamada retornou %d\n", need);
    if (need < 0)
    {
        perror("Erro na 1a chamada");
        va_end(args);
        return NULL;
    };

 

Se deu erro já diga qual foi e quando
 

    if (need > aloc - 1)    // nao cabe, vai truncar
    {
        printf("Necessarios %d, alocados %d. Realocando...\n", need, aloc);
        aloc = 1 + need; // ok, tanto quanto precisa + o zero
        char* p = realloc(dados, aloc);
        if (p == NULL)
        {
            perror("realloc falhou");
            va_end(args);
            return NULL;
        }
        printf("Alocados %d. Tentando de novo...\n", aloc);
        dados = p;
        need = vsnprintf(dados, aloc, format, args);
    }

 

Se não cabe aloca o necessário e tenta de novo.

 

Citação

vsnprintf() retorna o total de bytes necessários para entregar a formatação como pedida, sem considerar o zero final. printf() faz a mesma coisa.

 

 

main()

 

int main()
{
    printf("<%s>\n", dadosf("Essa string tem 120 caracteres desconsiderando o caractere nulo........................................................."));
    return 0;
}

 

Não misture as coisas. É um teste então prepare linha a linha. 

 

Prefira

int main()
{
    const char* o_teste = "\
Essa string tem 120 caracteres desconsiderando o caractere n\
ulo.........................................................\
";
    char* o_retorno = dadosf(o_teste);
    if (o_retorno == NULL)
    {
        printf(":( retornou NULL\n");
        return -1;
    }
    printf("Retorno:\n\"%s\"\n", o_retorno);
    free(o_retorno);
    return 0;
}

 

Assim

  • pode contar 2x60
  • salva o retorno
  • testa com mais controle
  • libera a memória alocada
  • é mais legível...

Pra que tanto pontinho? :D :D 

 

Um outro teste

 

Como seu programa não formata nada vou deixar um teste que mostra a ideia de vsnprintf().

 

Essa é a string de entrada
 

    char* message = "[10] '%s' [6] '%s' [10] '%s'";

 

E a ideia é inserir nos 3 "%s" outras strings...

 

int main()
{
    char* message = "[10] '%s' [6] '%s' [10] '%s'";
    char* digito = "0123456789";
    char* letra = "ABCDEF";
    printf("string original(%zd): \"%s\"\n", strlen(message)-6, message);
    size_t lim = strlen(message) - 6;
    testa_vsnprintf(lim + 10 + 6 + 10, message, digito, letra, digito, letra, digito);
    return 0;
}

 

Essas digito e letra. Mas no teste vão 6 strings. Para isso é um teste afinal. Não pode ter menos, mas pode ter mais que 3 parâmetros...

 

A saída do programa
 

string original(22): "[10] '%s' [6] '%s' [10] '%s'"
String: [[10] '0123456789' [6] 'ABCDEF' [10] '0123456789'  ] Disponivel: 49 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [10] '0123456789   ] Disponivel: 48 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [10] '012345678    ] Disponivel: 47 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [10] '01234567     ] Disponivel: 46 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [10] '0123456      ] Disponivel: 45 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [10] '012345       ] Disponivel: 44 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [10] '01234        ] Disponivel: 43 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [10] '0123         ] Disponivel: 42 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [10] '012          ] Disponivel: 41 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [10] '01           ] Disponivel: 40 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [10] '0            ] Disponivel: 39 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [10] '             ] Disponivel: 38 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [10]               ] Disponivel: 37 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [10]               ] Disponivel: 36 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [10                ] Disponivel: 35 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [1                 ] Disponivel: 34 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF' [                  ] Disponivel: 33 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF'                    ] Disponivel: 32 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF'                    ] Disponivel: 31 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDEF                     ] Disponivel: 30 Necessario: 48
String: [[10] '0123456789' [6] 'ABCDE                      ] Disponivel: 29 Necessario: 48
String: [[10] '0123456789' [6] 'ABCD                       ] Disponivel: 28 Necessario: 48
String: [[10] '0123456789' [6] 'ABC                        ] Disponivel: 27 Necessario: 48
String: [[10] '0123456789' [6] 'AB                         ] Disponivel: 26 Necessario: 48
String: [[10] '0123456789' [6] 'A                          ] Disponivel: 25 Necessario: 48
String: [[10] '0123456789' [6] '                           ] Disponivel: 24 Necessario: 48
String: [[10] '0123456789' [6]                             ] Disponivel: 23 Necessario: 48
String: [[10] '0123456789' [6]                             ] Disponivel: 22 Necessario: 48
String: [[10] '0123456789' [6                              ] Disponivel: 21 Necessario: 48
String: [[10] '0123456789' [                               ] Disponivel: 20 Necessario: 48
String: [[10] '0123456789'                                 ] Disponivel: 19 Necessario: 48

 

Conforme o espaço encolhe vsprinf() corta a saída, como esperado.
 

void testa_vsnprintf(size_t lim, const char* msg, ... )
{
    char* buffer = (char*)malloc(1+lim);
    va_list args;
    va_start(args, msg);
    for (size_t aloc = 1+lim; aloc > lim - 30; aloc -= 1)
    {
        int res = vsnprintf(buffer, aloc, msg, args);
        printf("String: [%-50s] Disponivel: %zd Necessario: %d\n", buffer, aloc, res);
    }
    va_end(args);
    free(buffer);
    return;
}

 

Sim, b0b1nh0 meu programa :) 

 

Spoiler

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void        testa_vsnprintf(size_t,const char*,...);

int main()
{
    char* message = "[10] '%s' [6] '%s' [10] '%s'";
    char* digito = "0123456789";
    char* letra = "ABCDEF";
    printf("string original(%zd): \"%s\"\n", strlen(message)-6, message);
    size_t lim = strlen(message) - 6;
    testa_vsnprintf(lim + 10 + 6 + 10, message, digito, letra, digito, letra, digito);
    return 0;
}

void testa_vsnprintf(size_t lim, const char* msg, ... )
{
    char* buffer = (char*)malloc(1+lim);
    va_list args;
    va_start(args, msg);
    for (size_t aloc = 1+lim; aloc > lim - 30; aloc -= 1)
    {
        int res = vsnprintf(buffer, aloc, msg, args);
        printf("String: [%-50s] Disponivel: %zd Necessario: %d\n", buffer, aloc, res);
    }
    va_end(args);
    free(buffer);
    return;
}
// fim de main.c

 

 

  • Amei 1
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...