Enviado em 01/05/2018 - 22:03h
Criei um gerenciador de lista (fila) em C que oferece suporte a estruturas de dados desconhecidas, as quais são definidas pelo programador durante o desenvolvimento. Internamente, a fila usa o tipo void* para armazenar o conteúdo da estrutura que, por sua vez, é armazenada dentro de cada struct Node. Já implementei algumas funções básicas como add(), del(), get(), first() e last()./* Estrutura definida pelo programador. */ struct Pessoa { char nome[11]; int idade; char sexo; float altura; }; /* Eis aqui o problemão! O programador precisará definir os offsets de cada campo para poder usar a fila. */ #define OFF_NOME 0 #define OFF_IDADE 11 #define OFF_SEXO OFF_IDADE+sizeof(int) #define OFF_ALTURA sizeof(struct Pessoa)-sizeof(float) int main() { struct Node *fila = 0; struct Pessoa pessoa; // cria a fila passando o tamanho da estrutura fila = fila_init(sizeof(struct Pessoa)); if(!fila) { puts("Erro na criação da fila!"); return -1; } // adiciona o primeiro nó strncpy(pessoa.nome, "Ana", sizeof(pessoa.nome)-1); pessoa.idade = 5; fila_adiciona(fila, (void*)&pessoa); // escreve novos valores no nó que se encontra no índice 0 fila_set_str (fila, 0, "Amanda", 10, OFF_NOME); fila_set_int (fila, 0, 50, OFF_IDADE); //.... return 0; }
/* Estrutura Node usada internamente pelo gerenciador */ struct Node { void *st; int st_size; struct Node *prox; }; int fila_set_str(struct Node *fila, int index, const char *s, int maxlen, int campo_offset) { unsigned char *pbST; char *pChar; pbST = (unsigned char*)fila_get(fila, index); if(pbST) { pChar = (char*)(pbST+campo_offset); strncpy(pChar, s, maxlen); } } void fila_set_int(struct Node *fila, int index, int valor, int campo_offset) { unsigned char *pbST; int *pInt; pbST = (unsigned char*)fila_get(fila, index); if(pbST) { pInt = (int*)(pbST+campo_offset); *pInt = valor; } }
Enviado em 03/05/2018 - 12:07h
O Phoemur foi muito feliz ao salientar que C não é a melhor linguagem para fazer esse tipo de coisa porque, embora seja possível fazê-las, vai dar tanto trabalho, e o código vai ficar tão cheio de artifícios (macros e conversões de tipos de ponteiros pra todo lado) que tende a ficar terrível de se ler e manter.#define QUEUE_SPECIALIZATION(data_type, new_type_name) \ /* Define o tipo “new_type_name” como uma estrutura anônima contendo um único */ \ /* campo, de modo que um ponteiro para a estrutura coincida numericamente com */ \ /* um ponteiro para o campo, permitindo converter um no outro facilmente. */ \ typedef struct { Node n; } new_type_name; \ \ /* Inicializa um objeto do tipo “new_type_name”. Note a conversão de tipo de ‘Node *’ */ \ /* para ‘new_type_name *’, que se vale da coincidência numérica da declaração acima. */ \ /* O operador de concatenação do preprocessador, “##“, é usado para gerar uma função */ \ /* cujo nome será “new_type_name_init”. Note ainda que, como esse será um tipo para */ \ /* dados específicos (“data_type”), a função de inicialização não precisa receber ar- */ \ /* gumentos, mas usa a designação de tipo de dado informada na macro. */ \ new_type_name *new_type_name##_init(void){ \ return (new_type_name *)fila_init(sizeof(data_type)); \ } \ \ /* Função para adicionar um novo elemento na fila especializada. Note que ele recebe */ \ /* um ponteiro para o tipo especializado, não para a lista genérica, mas chama a função */ \ /* genérica para realizar a adição. Note também que: */ \ /* (1) fila_add() deve sempre fazer uma cópia do objeto que recebe, a fim de evitar */ \ /* problemas caso o objeto original tenha um tempo de vida menor que o da fila; */ \ /* (2) o segundo argumento de fila_add() deve ser do tipo ‘const void *’ (e isso, de */ \ /* certo modo, reforça a necessidade de fazer cópia do dado); */ \ /* (3) não é necessária a conversão explícita do ponteiro para o dado para ‘const */ \ /* void *’, pois o C especifica que tal conversão é sempre possível e válida; */ \ /* (4) o tipo de retorno de fila_add() é int, a fim de indicar se a adição foi feita */ \ /* com sucesso ou se falhou, e esse valor é reencaminhado por esta função. */ \ int new_type_name##_add(new_type_name *start, const data_type *data){ \ return fila_add(&start->n, data); \ } \ \ /* Assumindo que fila_get() retorne o valor do campo ‘st’ no registro do tipo ‘Node’, */ \ /* esta função converte tal valor, que é um ponteiro do tipo ‘void *’, num ponteiro */ \ /* do tipo ‘data_type *’. Note que não é necessária conversão explícita, porque con- */ \ /* versões de “void *’ para qualquer outro tipo de ponteiro são automáticas em C. */ \ data_type *new_type_name##_get(new_type_name *start, size_t index){ \ return fila_get(&start->n, index); \ } \ \ /* Implementa especializações das demais funções de manipulação da fila, que você */ \ /* mesmo elencou (e.g. fila_first(), fila_last(), fila_del() etc.), seguindo o modelo */ \ /* de transformações usado nas funções acima. */ \ \ /* Uma versão um pouco mais segura da função ..._get() mostrada acima, que retorna */ \ /* apenas uma cópia do dado, em lugar de um ponteiro diretamente para ele. */ \ data_type new_type_name##_get_copy(new_type_name *start, size_t index){ \ return *new_type_name##_get(start, index); \ } \ /* Fim da macro. */
Enviado em 05/05/2018 - 05:52h
Paulo, obrigado pela sugestão do uso de macro, creio que era isso que faltava! Vou estudar melhor para poder adaptá-lo ao meu código. O container que eu havia criado era inicialmente uma fila de fato. Depois atualizei para suportar novas funções e estrutura personalizada e acabou se tornando um container qualquer. Você tem razão em me alertar que não é apropriado misturar os termos. Agradeço mais uma vez pela dica!Criar entrada (menuentry) ISO no Grub
Como gerar qualquer emoji ou símbolo unicode a partir do seu teclado
Instalar o VIM 9.1 no Debian 12
Como saber o range de um IP público?
Muitas dificuldades ao instalar distro Linux em Notebook Sony Vaio PCG-6131L (VPCEA24FM)
Slackpkg+ (Slackpkg Plus) está de volta!
Como dividir duas janelas igualmente e lado-a-lado na sua tela
Como redefinir o diretório Home? (5)
Problemas com adaptadores wifi no Zorin (1)
Ocomon 6.0.1 - Problemas ao editar configurações estendidas (7)