Eu tenho uma estrutura de dados como esta:
struct foo { int id; rota interna; int backup_route; int current_route; }
e uma função chamada update () que é usada para solicitar mudanças nele.
atualização (42, dont_care, dont_care, new_route);
isso é muito longo e se eu adicionar algo à estrutura eu tenho que adicionar um 'dont_care' para CADA chamada para atualizar (...).
Estou pensando em passar uma estrutura para ela, mas preencher a estrutura com 'dont_care' antecipadamente é ainda mais tedioso do que apenas soletrá-la na chamada de função. Posso criar a estrutura em algum lugar com valores padrão de dont care e apenas definir os campos que me interessam depois de declará-lo como uma variável local?
struct foo bar = {.id = 42, .current_route = new_route}; atualizar (& bar);
Qual é a maneira mais elegante de passar apenas as informações que desejo expressar para a função de atualização?
e eu quero que todo o resto seja padronizado como -1 (o código secreto para 'não me importo')
fonte
PTHREAD_MUTEX_INITIALIZER
usa isso também.Você pode alterar seu valor especial secreto para 0 e explorar a semântica de membro da estrutura padrão do C
irá então passar 0 como membros da barra não especificada no inicializador.
Ou você pode criar uma macro que fará a inicialização padrão para você:
fonte
<stdarg.h>
permite que você defina funções variáveis (que aceitam um número indefinido de argumentos, comoprintf()
). Eu definiria uma função que recebesse um número arbitrário de pares de argumentos, um que especifica a propriedade a ser atualizada e outro que especifica o valor. Use umenum
ou uma string para especificar o nome da propriedade.fonte
enum
variáveis para ostruct
campo? Hardcode it? Então esta função será aplicável apenas a específicosstruct
.Em vez disso, considere usar uma definição de macro de pré-processador:
Se sua instância de (struct foo) for global, você não precisa do parâmetro para isso, é claro. Mas estou supondo que você provavelmente tem mais de uma instância. Usar o bloco ({...}) é um GNU-ismo que se aplica ao GCC; é uma maneira agradável (segura) de manter as linhas juntas como um bloco. Se, posteriormente, você precisar adicionar mais macros, como verificação de validação de intervalo, não terá que se preocupar em quebrar coisas como instruções if / else e assim por diante.
Isso é o que eu faria, com base nos requisitos que você indicou. Situações como essa são uma das razões pelas quais comecei a usar muito o python; manipular parâmetros padrão e tal se torna muito mais simples do que nunca com C. (Eu acho que é um plug Python, desculpe ;-)
fonte
Um padrão que o gobject usa é uma função variada e valores enumerados para cada propriedade. A interface é semelhante a:
Escrever uma função varargs é fácil - consulte http://www.eskimo.com/~scs/cclass/int/sx11b.html . Basta combinar pares chave -> valor e definir os atributos de estrutura apropriados.
fonte
Visto que parece que você só precisa dessa estrutura para a
update()
função, não use uma estrutura para isso, ela apenas ofuscará sua intenção por trás dessa construção. Talvez você deva repensar porque está mudando e atualizando esses campos e definir funções ou macros separadas para essas "pequenas" mudanças.por exemplo
Ou, melhor ainda, escreva uma função para cada caso de alteração. Como você já notou, você não altera todas as propriedades ao mesmo tempo, portanto, torne possível alterar apenas uma propriedade por vez. Isso não só melhora a legibilidade, mas também ajuda a lidar com os diferentes casos, por exemplo, você não precisa verificar todos os "dont_care" porque você sabe que apenas a rota atual é alterada.
fonte
Que tal algo como:
com:
e:
e correspondentemente:
Em C ++, um padrão semelhante tem um nome que não me lembro agora.
EDIT : É chamado de Named Parameter Idiom .
fonte
Estou enferrujado com estruturas, então provavelmente estou faltando algumas palavras-chave aqui. Mas por que não começar com uma estrutura global com os padrões inicializados, copiá-la para sua variável local e depois modificá-la?
Um inicializador como:
Então, quando você quiser usá-lo:
fonte
Você pode resolver o problema com um X-Macro
Você mudaria sua definição de estrutura para:
E então você seria capaz de definir facilmente uma função flexível que define todos os campos como
dont_care
.Seguindo a discussão aqui , também se pode definir um valor padrão desta forma:
O que se traduz em:
E use como na resposta hlovdal , com a vantagem de que aqui a manutenção é mais fácil, ou seja, a alteração do número de membros da estrutura será atualizada automaticamente
foo_DONT_CARE
. Observe que a última vírgula "espúria" é aceitável .Eu aprendi o conceito de X-Macros pela primeira vez quando tive que resolver esse problema .
É extremamente flexível para novos campos sendo adicionados à estrutura. Se você tiver diferentes tipos de dados, poderá definir
dont_care
valores diferentes dependendo do tipo de dados: a partir daqui , você pode se inspirar na função usada para imprimir os valores no segundo exemplo.Se estiver tudo bem com uma
int
estrutura completa, você pode omitir o tipo de dados deLIST_OF_foo_MEMBERS
e simplesmente alterar a função X da definição da estrutura para#define X(name) int name;
fonte
X
e geralmente acrescentam_ENTRY
ao nome da lista, por exemplo#define LIST_SOMETHING LIST_SOMETHING_ENTRY(a1, a2, aN) \ LIST_SOMETHING_ENTRY(b1, b2, bN) ...
.A maneira mais elegante seria atualizar os campos de estrutura diretamente, sem ter que usar a
update()
função - mas talvez haja boas razões para usá-la que não aparecem na pergunta.Ou você pode, como sugeriu Pukku, criar funções de acesso separadas para cada campo da estrutura.
Caso contrário, a melhor solução que posso pensar é tratar um valor de '0' em um campo de estrutura como um sinalizador 'não atualizar' - então, basta criar uma função para retornar uma estrutura zerada e, em seguida, usar isso para atualizar.
No entanto, isso pode não ser muito viável, se 0 for um valor válido para campos na estrutura.
fonte