Ir ao conteúdo
  • Cadastre-se

C++ dificuldades em gerar codigo certo


herbertbahia

Posts recomendados

estou com o seguinte problema : estou precisando chamar uma função em que recebe 2 parametros: uma matriz de bytes e o comprimento da matriz.

o problema é que a minha matriz deu mais de 15 mil linhas

criei esse codigo para contar o comprimento da matriz porque havia gerado ela e armazenado em um txt

#include <stdio.h>
#include <stdlib.h>
int main()
{
    FILE *arq=fopen("matriz.txt","r");
    if (arq==NULL ){
        printf("Erro de abertura\n");
        system("pause");
        exit(1);
    }
    char letra;
    int cont=0;
    while( (letra = fgetc(arq)) != EOF )
    {
    //	printf(arq,"%c",letra);
        if(letra =='\\')cont++;
    }
    fclose(arq);
    return 0;
}

de ideia inicial pensei em colocar em um header só para ela porcausa do tamanho ou até ali mesmo no meio do código mas tive problemas no caminho dela tinha varias caracteres e simbolos como "*" que fizeram virar comentario e era muito difícil localizar e substituir cada um individualmente.

 

1111.png.d868a1706cd94c65477d99c5b31955e5.png

para resolver esse erro acredito que vou ter que juntar tudo na mesma linha

 

pois quando copio do txt para o meu ide ele fica em varias linhas

22222222.png.be8de1b290fe8bad73b3420cf85b0d4e.png

sera que a melhor maneira de tratar isso seria tentar criar um codigo tipo o que fiz acima para resolver no txt para depois jogar no ide? aceito dicas, sugestões para eu conseguir chamar essa função.

 

Link para o comentário
Compartilhar em outros sites

@devair1010 voce poderia me mostrar a maneira de juntar tudo na mesma linha la no txt pra eu copiar e color? porque estou fazendo isso no cb e quando chega a uma determinada quantidade de caracteres ele nao mostra todos caracteres de uma linha e mesmo se segurar ctrl e girar a bolinha do mouse para diminuir nao da pra ver tudo que esta na mesma linha então vou tentar resolver pelo txt mesmo para ver se vai funcionar.

 

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

2 minutos atrás, devair1010 disse:

@herbertbahia     mas Qual o problema de a matriz ter mais de quinze mil linhas ? , e você não poderia pesquisar no próprio arquivo txt não ? , 

Acho que ele quer algo do tipo:

char matriz[15][30] = {"linha 1", "linha 2", "linha 3", "linha 4", "linha 5", "linha 6",
                           "linha 7", "linha 8", "linha 9", "linha 10", "linha 11", "linha 12",
                           "linha 13", "linha 14", "linha 15"};

Com 15 linhas é fácil. Já com 15 mil...

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

@Flávio Pedroza na verdade eu vou ter que passar ela por parametro no formato dessa imagem que postei

3 horas atrás, herbertbahia disse:

22222222.png.be8de1b290fe8bad73b3420cf85b0d4e.png

 

acho que só preciso uma maneira de juntar todos caracteres do txt na mesma linha e evitar comentarios como // ou /* , depois eu abro o txt e copio e colo no ide nao preciso chamar o txt direto no programa

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

21 horas atrás, arfneto disse:

Pode explicar o que quer fazer e a estrutura do arquivo? É uma matriz esparsa? 

Ou algo sem estrutura? O que pretende fazer com os dados?

 

É pouca informação para sugerir algo. Ao menos para mim

então @arfneto preciso converter o .png do meu projeto e embutir no codigo para evitar ter que carregalos junto com o projeto já até conseguir fazer isso. por exemplo este é um cursor de um mouse e funciona 

loadFromMemory("\x89\x50\x4e\x47\xd\xa\x1a\xa\x0\x0\x0\xd\x49\x48\x44\x52\x0\x0\x0\x6\x0\x0\x0\x8\x8\x6\x0\x0\x0\xda\xc6\x8e\x38\x0\x0\x0\x37\x49\x44\x41\x54\x8\xd7\x65\xcc\xd1\xa\x0\x20\x8\x43\xd1\xbb\xfd\xff\x3f\xdb\x4b\xd9\x32\x41\x90\x1d\x19\x40\xed\x7d\xc6\x0\x55\xc5\x44\x9f\x63\xa2\xf3\x2b\xd1\xb3\xfb\xe0\x7\x92\x6e\x95\xa4\xe\xda\xb3\x25\x61\x1\x50\x1f\x13\x6\x81\x80\xaf\xc6\x0\x0\x0\x0\x49\x45\x4e\x44\xae\x42\x60\x82", 112);

mas to com dificuldade de fazer outras imagens ficarem assim para eu embutir

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

3 horas atrás, arfneto disse:

Vai converter para que formato?

para esse formato não sie bem qual é só sei que precisa ser assim

5 horas atrás, herbertbahia disse:

loadFromMemory("\x89\x50\x4e\x47\xd\xa\x1a\xa\x0\x0\x0\xd\x49\x48\x44\x52\x0\x0\x0\x6\x0\x0\x0\x8\x8\x6\x0\x0\x0\xda\xc6\x8e\x38\x0\x0\x0\x37\x49\x44\x41\x54\x8\xd7\x65\xcc\xd1\xa\x0\x20\x8\x43\xd1\xbb\xfd\xff\x3f\xdb\x4b\xd9\x32\x41\x90\x1d\x19\x40\xed\x7d\xc6\x0\x55\xc5\x44\x9f\x63\xa2\xf3\x2b\xd1\xb3\xfb\xe0\x7\x92\x6e\x95\xa4\xe\xda\xb3\x25\x61\x1\x50\x1f\x13\x6\x81\x80\xaf\xc6\x0\x0\x0\x0\x49\x45\x4e\x44\xae\x42\x60\x82", 112);

 

3 horas atrás, arfneto disse:

E onde entra o lance de 15 mil linhas? png não tem linhas

acho que a maneira que estava fazendo não é funcional preciso descobrir um método que funcione

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

3 minutos atrás, herbertbahia disse:

para esse formato não sie bem qual é só sei que precisa ser assim

loadFromMemory("\x89\x50\x4e\x47\xd\xa\x1a\xa\x0\x0\x0\xd\x49\x48\x44\x52\x0\x0\x0\x6\x0\x0\x0\x8\x8\x6\x0\x0\x0\xda\xc6\x8e\x38\x0\x0\x0\x37\x49\x44\x41\x54\x8\xd7\x65\xcc\xd1\xa\x0\x20\x8\x43\xd1\xbb\xfd\xff\x3f\xdb\x4b\xd9\x32\x41\x90\x1d\x19\x40\xed\x7d\xc6\x0\x55\xc5\x44\x9f\x63\xa2\xf3\x2b\xd1\xb3\xfb\xe0\x7\x92\x6e\x95\xa4\xe\xda\xb3\x25\x61\x1\x50\x1f\x13\x6\x81\x80\xaf\xc6\x0\x0\x0\x0\x49\x45\x4e\x44\xae\x42\x60\x82", 112);

Isso não é o formato. Você tem aí um char[] e um byte 112. Se a primeira parte é simplesmente o conteúdo do arquivo e 112 é algum número mágico, aí sim temos um formato. É isso?

 

Se for isso aí te digo umas maneiras de fazer isso :) se não for me diga como passar do arquivo original para essa string aí e vemos uma opção

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

@arfneto sobre essa do cursor eu ja achei pronto mas to quebrando a cabeça pra fazer isso com outras imagens como disse a função que vou usar 

Em 19/07/2020 às 11:15, herbertbahia disse:

recebe 2 parametros: uma matriz de bytes e o comprimento da matriz.

então preciso tranformar a imagem nisso daí pesquisando achei algumas maneiras de converter mas nao to conseguindo colocar isso em prática

https://lvgl.io/tools/imageconverter

 

 

https://www.google.com/search?q=png+to+array+cpp&o que=png+to+array+cpp&aqs=chrome..69i57j33.5148j0j4&sourceid=chrome&ie=UTF-8

 

fico uito grato se me ajudar a fazer isso

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

A função abaixo cria a declaração de um vetor do C em texto plano a partir de um arquivo binário qualquer que você pode copiar-colar no teu código, bastando mudar o nome do array. Para passar o vetor como argumento para a função loadMemory(), que talvez esteja esperando um ponteiro do tipo char*, faça: loadFromMemory((char*)nomeDoArray, sizeof(nomeDoArray));
você pode mudar o valor da constante MAXCOLS para outro numero se preferir.

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

/* Input.: arquivo binario
   Output:
    const unsigned char nomeDoArray[]={
         0x00,0x11,0x22,0x33,0x44,
         0x55,0x66,0x77,0x88,0x99
    };
*/
char* ArquivoParaVetorDeBytesC(const char *arqNome, char **dest)
{
    const int MAXCOLS = 16;
    FILE *arq = fopen(arqNome,"rb");
    fseek(arq, 0, SEEK_END);
    size_t arqTam = ftell(arq);
    rewind(arq);

    unsigned char b;
    char sByte[16];
    int j = 0;
    size_t bufTam = arqTam * 16;
    char *buf = (char*)malloc(bufTam);
    memset(buf, 0, bufTam);

    // adiciona a declaracao do array
    strcat(buf, "const unsigned char nomeDoArray[]={\n");
    while( fread(&b, sizeof(b), 1, arq) == 1 )
    {
        if (j < MAXCOLS)
        {
            sprintf(sByte, "0x%02X,", b);
            strcat(buf, sByte);        
            j++;
        }
        else
        {
            sprintf(sByte, "0x%02X,\n", b);
            strcat(buf, sByte);    
            j = 0;
        }
    }    
    strcat(buf, "\n};");
    *dest = buf;    
    return *dest;
}

int main()
{
    char *buf = NULL;
    ArquivoParaVetorDeBytesC("imagem.png", &buf);
    printf("%s\n", buf);
    
    // Libera a memoria a memoria apontada por buf, que foi alocada dentro da funcao.
    free(buf);
    
    return 0;
}    

    

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

1 hora atrás, herbertbahia disse:

você é o cara

 

Não não...

 

Veja a sugestão acima de @holifaca 

 

Vou te mandar um programa que vai ajudar a entender uma solução possível pra isso, e comum. Ao menos eu já usei incontáveis vezes.

 

O lance de LoadFromMemory() no seu caso é replicar o que o sistema faz com os chamados resources ---  e o sistema faz isso de modo transparente em geral. No geral o que você quer fazer é o que está descrito aqui https://docs.microsoft.com/en-us/windows/win32/menurc/about-resource-files mas sem arquivos .rc e sem o Microsoft Resource Compiler. Então se pode imitar os caras...

 

Na maioria dos casos o que você quer é inserir coisas, como sons e imagens, no executável no início do programa. Lendo do disco, e depois usar sempre a partir da memória. Mas você quer embutir isso direto no executável para não ter que distribuir os arquivos que seriam lidos na carga do programa.

 

Vou te mostrar uma classe depois com um jeito de fazer isso e um programa que eu postei outro dia aqui que ajuda a entender a simples ideia e aí você acerta pra seu uso. 

 

Em resumo você declara uma classe Recurso que faz o meio de campo. Essa classe cria um recurso e aí você pode usar um vetor ou um mapa ou qualquer coisa para guardar os tais recursos. Ou mesmo nada se forem poucos recursos, Talvez algo assim já resolva:

 

#pragma once
#include <iostream>
using namespace std;

class Recurso
{
public:
	std::string nome;
private:
	unsigned char* conteudo;
	int tamanho;
public:
	Recurso(string, int, unsigned char*);
	~Recurso() { delete[] conteudo; };
	int Dump() {};
};	// class

 

No construtor do Recurso você aloca a memória para ele e carrega o valor. E lá você passa conteudo que é liberado no destrutor;

 

O método Dump() mostra na tela os bytes para você saber que carregou certinho :) 

 

Uma declaração usando o construtor seria algo assim

//Magica
int magica = 0;
Recurso    png1("MeuPng1", 8, "12345678");

E agora?


Em main() você vai ter uma série de declarações de recursos, e na declaração vai estar tudo acertado já.


Imagine um arquivo assim

# recursos
teste.png	png1
azul.ico	ico1
outro.png	png2

E você faz seu programa normalmente, já assumindo que os recursos estão lá, e pode usar LoadFromMemory() e tal.

 

Como costurar isso?


Você preprocessa seu programa fonte usando o arquivo de recursos acima e cria as declarações certinhas a partir daquele comentário //Magica e insere as declarações para os recursos. E muda o valor do int magica também.


Como seria esse programa


O int magica serve para você em runtime saber se não está rodando um fonte que não foi preprocessado. Ao ajustar o programa você só vai gerar um trecho de código, como se fosse um #define. Mas então se magica for ainda 0 em tempo de execução é porque você está usando um fonte compilado sem a inserção dos recursos. Deu pra entender?

 

E a partir daí o processo é um simples loop: para cada arquivo em recursos você vai no disco e vê o tamanho dele e gera a declaração de acordo: o nome que está no arquivo de entrada, o tamanho que leu no disco e a string que vai criar a partir do conteúdo.

 

Assim você cria os recursos no stack usando alocação dinâmica, a memória já é liberada no final sem você fazer nada e a vida segue. Se usasse como estático poderia ter problemas com o tamanho do heap.

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

6 horas atrás, holifaca disse:

A função abaixo cria a declaração de um vetor do C em texto plano a partir de um arquivo binário qualquer que você pode copiar-colar no teu código, bastando mudar o nome do array. Para passar o vetor como argumento para a função loadMemory(), que talvez esteja esperando um ponteiro do tipo char*, faça: loadFromMemory((char*)nomeDoArray, sizeof(nomeDoArray));
você pode mudar o valor da constante MAXCOLS para outro numero se preferir.


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

/* Input.: arquivo binario
   Output:
    const unsigned char nomeDoArray[]={
         0x00,0x11,0x22,0x33,0x44,
         0x55,0x66,0x77,0x88,0x99
    };
*/
char* ArquivoParaVetorDeBytesC(const char *arqNome, char **dest)
{
    const int MAXCOLS = 16;
    FILE *arq = fopen(arqNome,"rb");
    fseek(arq, 0, SEEK_END);
    size_t arqTam = ftell(arq);
    rewind(arq);

    unsigned char b;
    char sByte[16];
    int j = 0;
    size_t bufTam = arqTam * 16;
    char *buf = (char*)malloc(bufTam);
    memset(buf, 0, bufTam);

    // adiciona a declaracao do array
    strcat(buf, "const unsigned char nomeDoArray[]={\n");
    while( fread(&b, sizeof(b), 1, arq) == 1 )
    {
        if (j < MAXCOLS)
        {
            sprintf(sByte, "0x%02X,", b);
            strcat(buf, sByte);        
            j++;
        }
        else
        {
            sprintf(sByte, "0x%02X,\n", b);
            strcat(buf, sByte);    
            j = 0;
        }
    }    
    strcat(buf, "\n};");
    *dest = buf;    
    return *dest;
}

int main()
{
    char *buf = NULL;
    ArquivoParaVetorDeBytesC("imagem.png", &buf);
    printf("%s\n", buf);
    
    // Libera a memoria a memoria apontada por buf, que foi alocada dentro da funcao.
    free(buf);
    
    return 0;
}    

nao entendir direito a sua explicação ou então nao conseguir colocar para funcionar

adicionado 1 minuto depois
5 horas atrás, arfneto disse:

Não não...

 

Veja a sugestão acima de @holifaca 

 

Vou te mandar um programa que vai ajudar a entender uma solução possível pra isso, e comum. Ao menos eu já usei incontáveis vezes.

 

O lance de LoadFromMemory() no seu caso é replicar o que o sistema faz com os chamados resources ---  e o sistema faz isso de modo transparente em geral. No geral o que você quer fazer é o que está descrito aqui https://docs.microsoft.com/en-us/windows/win32/menurc/about-resource-files mas sem arquivos .rc e sem o Microsoft Resource Compiler. Então se pode imitar os caras...

 

Na maioria dos casos o que você quer é inserir coisas, como sons e imagens, no executável no início do programa. Lendo do disco, e depois usar sempre a partir da memória. Mas você quer embutir isso direto no executável para não ter que distribuir os arquivos que seriam lidos na carga do programa.

 

Vou te mostrar uma classe depois com um jeito de fazer isso e um programa que eu postei outro dia aqui que ajuda a entender a simples ideia e aí você acerta pra seu uso. 

 

Em resumo você declara uma classe Recurso que faz o meio de campo. Essa classe cria um recurso e aí você pode usar um vetor ou um mapa ou qualquer coisa para guardar os tais recursos. Ou mesmo nada se forem poucos recursos, Talvez algo assim já resolva:

 


#pragma once
#include <iostream>
using namespace std;

class Recurso
{
public:
	std::string nome;
private:
	unsigned char* conteudo;
	int tamanho;
public:
	Recurso(string, int, unsigned char*);
	~Recurso() { delete[] conteudo; };
	int Dump() {};
};	// class

 

No construtor do Recurso você aloca a memória para ele e carrega o valor. E lá você passa conteudo que é liberado no destrutor;

 

O método Dump() mostra na tela os bytes para você saber que carregou certinho :) 

 

Uma declaração usando o construtor seria algo assim


//Magica
int magica = 0;
Recurso    png1("MeuPng1", 8, "12345678");

E agora?


Em main() você vai ter uma série de declarações de recursos, e na declaração vai estar tudo acertado já.


Imagine um arquivo assim


# recursos
teste.png	png1
azul.ico	ico1
outro.png	png2

E você faz seu programa normalmente, já assumindo que os recursos estão lá, e pode usar LoadFromMemory() e tal.

 

Como costurar isso?


Você preprocessa seu programa fonte usando o arquivo de recursos acima e cria as declarações certinhas a partir daquele comentário //Magica e insere as declarações para os recursos. E muda o valor do int magica também.


Como seria esse programa


O int magica serve para você em runtime saber se não está rodando um fonte que não foi preprocessado. Ao ajustar o programa você só vai gerar um trecho de código, como se fosse um #define. Mas então se magica for ainda 0 em tempo de execução é porque você está usando um fonte compilado sem a inserção dos recursos. Deu pra entender?

 

E a partir daí o processo é um simples loop: para cada arquivo em recursos você vai no disco e vê o tamanho dele e gera a declaração de acordo: o nome que está no arquivo de entrada, o tamanho que leu no disco e a string que vai criar a partir do conteúdo.

 

Assim você cria os recursos no stack usando alocação dinâmica, a memória já é liberada no final sem você fazer nada e a vida segue. Se usasse como estático poderia ter problemas com o tamanho do heap.

acho que conseguir entender o que tentou explicar mas nao conseguir carregar nem 1 arquivo como vou carregar varios?

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

4 minutos atrás, herbertbahia disse:

acho que conseguir entender o que tentou explicar mas nao conseguir carregar nem 1 arquivo como vou carregar varios?

 

É a mesma coisa.

 

Entendeu que vai girar tudo em torno do arquivo de recursos? 

# recursos
teste.png	png1
azul.ico	ico1
outro.png	png2

Você vai escrever um programa simples, em C ou C++ ou awk ou sei lá. Esse programa vai ler seu programa C++ e gerar as declarações que estão faltando, a partir dessa lista que está no arquivo e lendo os arquivos no disco e preenchendo a declaração das classes. Só isso.

 

Quando você compilar o programa vai ter um código que que cria as instâncias da classe que te mostrei, aloca memória para os png e tudo que precisar. No código você não trata isso mais. Está tudo lá. Ao sair do programa os destrutores vão liberar a memória.

 

Veja esse exemplo em C de algo parecido: esse programa você roda assim

x saida.txt

E ele cria saida.txt. Claro que é como qualquer outro programa de console: o argumento é o nome do arquivo de saída.


Eis o que ele gera

const char idx[256] =
{

  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   0,   2,   0,
  3,   4,   5,   6,   7,   8,   9,  10,  11,  12,   0,   0,   0,   0,   0,   0, 
  0,  13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27, 
 28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,   0,   0,   0,   0,   0, 
  0,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53, 
 54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,   0,   0,   0,   0,   0, 
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0

}; // ARFNeto '20

E serve para um milhão de coisas. É uma tabela de referência. Esse é um exemplo e não me lembro agora para que era. Isso é o que sai na tela ao rodar o programa:


Gerado trecho de codigo em 'saida.txt'

Eis o programa

#define _CRT_SECURE_NO_WARNINGS
#include "stdio.h"

int main(int argc, char** argv)
{
	FILE* saida = stdout;
	int disco = 0; // gerou arquivo?
	if (argc > 1)
	{
		saida = fopen(argv[1], "w");
		disco = 1;
	};
	int out = 1;
	fprintf(saida, "\nconst char idx[256] =\n{\n\n");
	for (int i = 0; i < 44; i = i + 1)
	{	// 44 = . e o primeiro valido: idx = 1
		fprintf(saida, "%3d, ", 0);
		if (out % 16 == 0) fprintf(saida, "\n");
		out += 1;
	};
	fprintf(saida, "  1,   0,   2,   0,\n");
	// 46 = , idx = 2 48 = '0', idx = 3
	out += 4;
	// loop agora para 0 a 9, idx = 3..11
	int idx = 3;
	for (int i = '0'; i <= '9'; i += 1, idx += 1)
	{
		fprintf(saida, "%3d, ", idx);
		if (out % 16 == 0) fprintf(saida, "\n");
		out += 1;
	};
	// agora o intervalo entre '9'e 'A', 58..64
	for (int i = 58; i < 65; i += 1)
	{
		fprintf(saida, "%3d, ", 0);
		if (out % 16 == 0) fprintf(saida, "\n");
		out += 1;
	};
	// agora as letras de A a Z
	for (int i = 'A'; i <= 'Z'; i += 1, idx += 1)
	{
		fprintf(saida, "%3d, ", idx);
		if (out % 16 == 0) fprintf(saida, "\n");
		out += 1;
	};
	// agora o intervalo entre 'Z' e 'a', 91..96
	for (int i = 91; i <= 96; i += 1)
	{
		fprintf(saida, "%3d, ", 0);
		if (out % 16 == 0) fprintf(saida, "\n");
		out += 1;
	};
	// agora as letras de 'a' a 'z'
	for (int i = 'a'; i <= 'z'; i += 1, idx += 1)
	{
		fprintf(saida, "%3d, ", idx);
		if (out % 16 == 0) fprintf(saida, "\n");
		out += 1;
	};
	// agora o intervalo de 'z' ate o fim
	for (int i = 123; i < 255; i += 1)
	{
		fprintf(saida, "%3d, ", 0);
		if (out % 16 == 0) fprintf(saida, "\n");
		out += 1;
	};
	fprintf(saida, "  0\n\n}; // ARFNeto '20\n");
	if (disco)
	{
		fprintf(stderr, "\nGerado trecho de codigo em '%s'\n",
			argv[1]);
	};
	return 0;
};	// main()

É só pra você entender a ideia.

 

Como usar isso:

 

Vai ser um #include em seu programa. Nada mais.

 

Veja um programa que usa isso

#include "stdio.h"
#include "saida.txt"
int main()
{
	int l = 0;
	printf("\n");
	for (int i = 0; i < 256; i += 1)
		if (idx[i] != 0) // tem representacao
		{
			printf("  %2d:%3d %c", idx[i], i, i);
			if (l % 8 == 7) printf("\n");
			l += 1;
		};	// if()
	printf("\n");
};

E mostra o resultado do look-up


   1: 44 ,   2: 46 .   3: 48 0   4: 49 1   5: 50 2   6: 51 3   7: 52 4   8: 53 5
   9: 54 6  10: 55 7  11: 56 8  12: 57 9  13: 65 A  14: 66 B  15: 67 C  16: 68 D
  17: 69 E  18: 70 F  19: 71 G  20: 72 H  21: 73 I  22: 74 J  23: 75 K  24: 76 L
  25: 77 M  26: 78 N  27: 79 O  28: 80 P  29: 81 Q  30: 82 R  31: 83 S  32: 84 T
  33: 85 U  34: 86 V  35: 87 W  36: 88 X  37: 89 Y  38: 90 Z  39: 97 a  40: 98 b
  41: 99 c  42:100 d  43:101 e  44:102 f  45:103 g  46:104 h  47:105 i  48:106 j
  49:107 k  50:108 l  51:109 m  52:110 n  53:111 o  54:112 p  55:113 q  56:114 r
  57:115 s  58:116 t  59:117 u  60:118 v  61:119 w  62:120 x  63:121 y  64:122 z

Espero que tenha ajudado você a entender:

 

Você vai escrever um programa assim, que vai pegar seu programa em C++ e seu arquivo de recursos e vai gerar as declarações que estão faltando, já certinhas...

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

Isso que eu te mostrei dá o ciclo completo: um programa em qualquer linguagem gera a tabela idx[256] que incorpora a lógica no momento. O programa que vai usar apenas inclui o texto que foi gerado. E o programa resultante já incorpora toda a lógica da tabela. É muito produtivo.

 

Aqui tem arquivos de entrada então recomendo usar o arquivo de recursos. Claro que na verdade nem precisa existir isso, mas assim é mais flexível e mais fácil de testar...

 

Veja esse resultado 

[ usando void* ]
(*) Recurso png1 com 64 bytes
21 42 43 44 35 36 37 38 41 42 43 44 35 36 37 38
41 42 43 44 35 36 37 38 41 42 43 44 35 36 37 38
41 42 43 44 35 36 37 38 41 42 43 44 35 36 37 38
41 42 43 44 35 36 37 38 41 42 43 44 35 36 37 21


[ usando unsigned char const* ]
(*) Recurso png2 com 40 bytes
21 42 43 44 35 36 37 38 41 42 43 44 35 36 37 38
41 42 43 44 35 36 37 38 41 42 43 44 35 36 37 38
41 42 43 44 35 36 37 38 41 42 43 44 35 36 37 38
41 42 43 44 35 36 37 38 41 42 43 44 35 36 37 21

Deste programa em C++

#include <iostream>
using namespace std;
#include "Recurso.h"

int main()
{
	unsigned char teste[65] = "\
!BCD5678ABCD5678\
ABCD5678ABCD5678\
ABCD5678ABCD5678\
ABCD5678ABCD567!";
	void* outro = &teste[0];
	string str = "png1";
	Recurso um(str, sizeof(teste)-1, outro);
	um.Dump();

	Recurso dois("png2", 64, (unsigned char*)"\
!BCD5678ABCD5678\
ABCD5678ABCD5678\
ABCD5678ABCD5678\
ABCD5678ABCD567!");
	dois.Dump();

};

Aqui você vê duas maneiras de usar, e graças ao polimorfismo você tem os dois construtores já. E o construtor padrão foi apagado para evitar que você esqueça e declare algum recurso errado. Veja a classe abaixo e confirme se entendeu.

 

Uma implementação mínima, usando o construtor 2, unsigned char*

class Recurso
{
public:
private:
	unsigned char* conteudo;
	std::string nome;
	int tamanho;
public:
	Recurso() = delete;
	Recurso(string, int, void*);
	Recurso(string, int, unsigned char const*);
	~Recurso();
	int Dump();
};	// class

E o arquivo de recurso recurso.txt tendo

# uso: arquivo<TAB>instancia
teste.txt	dois

E o arquivo teste.txt tendo 64 bytes e esse conteúdo

!BCD5678ABCD5678
ABCD5678ABCD5678
ABCD5678ABCD5678
ABCD5678ABCD567!

Sem as quebras de linha :) 

 

O programa final teria só isso

#include <iostream>
using namespace std;
#include "Recurso.h"

int main()
{
#include "trecho.txt"
	dois.Dump();

};

E o  arquivo trecho.txt  gerado seria 

	Recurso dois("dois", 64, (unsigned char*)"\
!BCD5678ABCD5678\
ABCD5678ABCD5678\
ABCD5678ABCD5678\
ABCD5678ABCD567!");

E mostraria

[ usando unsigned char const* ]
(*) Recurso dois com 64 bytes
21 42 43 44 35 36 37 38 41 42 43 44 35 36 37 38
41 42 43 44 35 36 37 38 41 42 43 44 35 36 37 38
41 42 43 44 35 36 37 38 41 42 43 44 35 36 37 38
41 42 43 44 35 36 37 38 41 42 43 44 35 36 37 21

Entendeu?

 

O que Dump() mostra é o conteúdo em hexadecimal do que estava no arquivo original teste.txt no disco. E isso é para ter certeza de que está rodando certo.

 

Para gerar um loadFromMemory() é igualzinho, apenas vai colocar o tamanho depois da vírgula e fechar com ");"


	loadFromMemory("\
!BCD5678ABCD5678\
ABCD5678ABCD5678\
ABCD5678ABCD5678\
ABCD5678ABCD567!", 

64 );

 

 

  • Curtir 2
Link para o comentário
Compartilhar em outros sites

@arfneto estava pensando em fazer algo assim

 

#include <iostream> 

using namespace std;

class Recurso{
	public:
	private:
};
Recurso::Recurso(string variavel, string arquivo) :
	nome(variavel), tamanho(0), conteudo(NULL)
{
	conteudo = NULL;
	namespace disco = std::filesystem;
	if (!disco::exists(arquivo)) return;
	tamanho = (int) disco::file_size(arquivo);
	if (tamanho == 0) return;
	ifstream ent{ arquivo, ifstream::binary };
	if (!ent.good()) return;
	conteudo = new unsigned char[tamanho];
	for (int i = 0; i < tamanho; i += 1)
		ent.read((char*)(conteudo+i), 1);
};

int main() { 
 };

 

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

🤔

 

Muito bem!

 

C++ é muito flexível para criar abstrações e modelos assim rapidamente. Talvez porque tenha sido escrita exatamente para isso, como sempre diz o Prof. Stroustrup, que criou C++: abstrações de custo zero.

 

Se você tem a classe recurso pode ir construindo em torno dela o que precisa. É muito mais simples. Mesmo.

 

Uma classe assim:

class Recurso
{
	friend void loadFromMemory(Recurso*);
private:
	unsigned char* conteudo;
	std::string nome;
	int tamanho;
public:
	Recurso() = delete;
	Recurso(string, string); // variavel, arq
	Recurso(string, int, void*); 
	Recurso(string, int, unsigned char const*);
	~Recurso();
	int Dump();
	int GeraTrecho(string);
	int GeraDeclaracao(string,string,string);

};	// class

Você vê que há 3 maneiras de criar um Recurso, mas podiam ser 300. Ou uma só. E a classe é isso: dados e comportamento. Variáveis e métodos.

 

As variáveis

Até aqui apenas o óbvio: um nome, um tamanho e o conteúdo que corresponde ao.... conteúdo. Sem novidades. Tanto faz o que é: um cursor, um ícone, uma imagem, um texto, são só bytes.


Os métodos

Para testar, o que é necessário? Criar um menu e pedir pro usuário teclar valores? Não. Claro que não. Os dois primeiros construtores usam um vetor de char comum, ou um ponteiro void para alguma coisa, e transferem cegamente para o recurso.


Dump()

E dump mostra os valores em hexadecimal na tela, 16 por linha. E assim dá pra conferir se está tudo funcionando.

Depois dos testes, um terceiro construtor

	Recurso tres("png1", "trecho.txt");

E daí?

 

Já que provavelmente funciona porque foi testado com os Dump() e os dois primeiros construtores, o próximo passo é o simples: carregar o Recurso direto a partir do arquivo como acima. Assim poderia chamar por exemplo loadFromMemory() direto, com o recurso carregado a partir do arquivo.

Geralmente é isso que se quer: na carga do programa carrega os recursos do disco para a memória e a partir daí trabalha só com a memória. Mas no caso aqui o que se quer é encapsular o recurso totalmente no executável para não precisar distribuir mais nada. 

Mas se esse método carrega o Recurso se pode gerar a declaração de qualquer maneira apenas lendo a classe. Por exemplo:

    tres.GeraDeclaracao("quatro","primeiroPNG","codigo2.txt");

 

Essa implementação cria o arquivo "codigo2.txt" a partir do que foi carregado a partir de "trecho.txt" na chamada anterior.

 

Exemplo:

trecho.txt

1234567890abcdefghABCDEFGH

codigo2.txt

	Recurso  quatro("primeiroPNG", 26, (unsigned char*)"\ 
\x31\x32\x33\x34\x35\x36\x37\x38\x39\x30\x61\x62\x63\x64\x65\x66\
\x67\x68\x41\x42\x43\x44\x45\x46\x47\x48\
");

E assim fecha o círculo. No programa distribuído basta usar #include para cada recurso.

 

E se fosse gerar loadFromMemory()?

 

A lógica é exatamente a mesma. Mas o resultado é melhor porque não precisa da classe Recurso no programa de destino. E usando da maneira anterior o executável teria 2 cópias do recurso a toa. Provavelmente numa implementação séria se escreveria GeraDelcaracao() para gerar uma declaração estática. Sugiro fazer isso.

 

E como seria gerar uma declaração assim?

int Recurso::GeraDeclaracao(
	string variavel, 
	string nome, 
	string arquivo)
{
	cerr << std::dec << "Gerando declaracao para '" << nome <<
		"'\n\tda instancia '" << variavel <<
		"'\n\tda classe 'Recurso'\n\tEm '" <<
		arquivo <<
		"' com '"<< tamanho << " bytes" <<
		endl;
	ofstream saida{ arquivo };
	int nl = 16; // quantos por linha
	/*
	Recurso variavel ("nome", tamanho, (unsigned char*)"\
	*/
	saida << "\tRecurso  " << variavel << "(\"" <<
		nome << "\", " << tamanho << 
		", (unsigned char*)\"\\ " << endl;
	for (int i = 0; i < tamanho; i += 1)
	{
		saida << "\\x" << hex << setw(2) <<
			setfill('0') << (int)conteudo[i];
		if ((i + 1) % nl == 0) saida << "\\" << endl;
	};
	saida << "\\" << endl;
	saida << "\");\n" << endl;
	saida.close();
	return 0;
};

É bem imediato: basta ler de um lugar e gravar no outro.

 

E loadFromMemory()?


Pode ser mais simples, como

int Recurso::GeraTrecho(string arquivo)
{
	cerr << std::dec << "Gerando codigo para '" << nome <<
		"' em '" << arquivo <<
		"' Tamanho: " << tamanho << " bytes" <<
		endl;
	ofstream saida{ arquivo };
	int nl = 16; // quantos por linha
	saida << "\tloadFromMemory(\"\\" << endl;
	for (int i = 0; i < tamanho; i += 1)
	{
		saida << "\\x" << hex << setw(2) <<
			setfill('0') << (int)conteudo[i];
		if ((i + 1) % nl == 0) saida << "\\" << endl;
	};
	saida << "\\" << endl;
	saida << "\", " << dec << tamanho <<
		");\n" << endl;
	saida.close();
	return 0;
};

 

Citação

estou postando isso tudo porque (1) é uma maneira de criar uma abstração em C++ e (2) gerar código compilável em qualquer linguagem, então pode ser útil para muitos casos e pessoas. Ou ao menos assim eu imagino ;) 

 

Eis um programa de teste em C++

Spoiler

#include <cstring>
#include <filesystem>
#include <fstream>
#include <iomanip>
#include <iostream>
using namespace std;

class Recurso
{
	friend void loadFromMemory(Recurso*);
private:
	unsigned char* conteudo;
	std::string nome;
	int tamanho;
public:
	Recurso() = delete;
	Recurso(string, string); // variavel, arq
	Recurso(string, int, void*); 
	Recurso(string, int, unsigned char const*);
	~Recurso();
	int Dump();
	int GeraTrecho(string);
	int GeraDeclaracao(string,string,string);

};	// class

int main()
{
	Recurso tres("png1", "trecho.txt");
	tres.Dump();
	tres.GeraTrecho("codigo1.txt");
	tres.GeraDeclaracao("quatro","primeiroPNG","codigo2.txt");
	return 0;
};


using namespace std;

Recurso::Recurso(
	string nome,
	int tamanho,
	unsigned char const* cont) :
	nome(nome), tamanho(tamanho)
{
	cout << "[ usando unsigned char const* ]" << endl;
	conteudo = new unsigned char[tamanho];
	memcpy(conteudo, cont, tamanho);
};
Recurso::Recurso(
	string nome,
	int tamanho,
	void* cont) :
	nome(nome), tamanho(tamanho)
{
	cout << "[ usando void* ]" << endl;
	conteudo = new unsigned char[tamanho];
	memcpy(conteudo, cont, tamanho);
};

Recurso::~Recurso() { delete[] conteudo; };

Recurso::Recurso(string variavel, string arquivo) :
	nome(variavel), tamanho(0), conteudo(NULL)
{	// o simples: carrega o arquivo na memoria
	conteudo = NULL;
	namespace disco = std::filesystem;
	if (!disco::exists(arquivo)) return;
	tamanho = (int) disco::file_size(arquivo);
	if (tamanho == 0) return;
	ifstream ent{ arquivo, ifstream::binary };
	if (!ent.good()) return;
	conteudo = new unsigned char[tamanho];
	for (int i = 0; i < tamanho; i += 1)
		ent.read((char*)(conteudo+i), 1);
};

int Recurso::Dump()
{
	cout << "(*) Recurso " << nome <<
		" com " << tamanho << " bytes" << endl;
	for (int i = 0; i < tamanho; i += 1)
	{
		cout << setw(2) << std::hex << (int) conteudo[i] << " ";
		if ((i + 1) % 16 == 0) cout << endl;
	};
	cout << "\n\n";
	return 0;
};

int Recurso::GeraTrecho(string arquivo)
{
	cerr << std::dec << "Gerando codigo para '" << nome <<
		"' em '" << arquivo <<
		"' Tamanho: " << tamanho << " bytes" <<
		endl;
	ofstream saida{ arquivo };
	int nl = 16; // quantos por linha
	saida << "\tloadFromMemory(\"\\" << endl;
	for (int i = 0; i < tamanho; i += 1)
	{
		saida << "\\x" << hex << setw(2) <<
			setfill('0') << (int)conteudo[i];
		if ((i + 1) % nl == 0) saida << "\\" << endl;
	};
	saida << "\\" << endl;
	saida << "\", " << dec << tamanho <<
		");\n" << endl;
	saida.close();
	return 0;
};

int Recurso::GeraDeclaracao(
	string variavel, 
	string nome, 
	string arquivo)
{
	cerr << std::dec << "Gerando declaracao para '" << nome <<
		"'\n\tda instancia '" << variavel <<
		"'\n\tda classe 'Recurso'\n\tEm '" <<
		arquivo <<
		"' com '"<< tamanho << " bytes" <<
		endl;
	ofstream saida{ arquivo };
	int nl = 16; // quantos por linha
	/*
	Recurso variavel ("nome", tamanho, (unsigned char*)"\
	*/
	saida << "\tRecurso  " << variavel << "(\"" <<
		nome << "\", " << tamanho << 
		", (unsigned char*)\"\\ " << endl;
	for (int i = 0; i < tamanho; i += 1)
	{
		saida << "\\x" << hex << setw(2) <<
			setfill('0') << (int)conteudo[i];
		if ((i + 1) % nl == 0) saida << "\\" << endl;
	};
	saida << "\\" << endl;
	saida << "\");\n" << endl;
	saida.close();
	return 0;
};

void loadFromMemory(Recurso* R)
{
	cout << "Recurso " << R->nome << endl;
	return;
};

 


A saída de um sofisticado programa
 

image.png.bf727191feb8e9b13264b82c62834e9d.png

 

O programa

int main()
{
	Recurso tres("png1", "trecho.txt");
	tres.Dump();
	tres.GeraTrecho("codigo1.txt");
	tres.GeraDeclaracao("quatro","primeiroPNG","codigo2.txt");
	return 0;
};

 

  • Curtir 1
  • Obrigado 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...

 

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!