J'ai une structure de données comme celle-ci:
struct toto { int id; int route; int backup_route; int current_route; }
et une fonction appelée update () qui est utilisée pour demander des modifications.
mise à jour (42, dont_care, dont_care, nouvelle_route);
c'est vraiment long et si j'ajoute quelque chose à la structure je dois ajouter un 'dont_care' à CHAQUE appel pour mettre à jour (...).
Je pense plutôt lui passer une structure, mais remplir au préalable la structure avec 'dont_care' est encore plus fastidieuse que de simplement l'épeler dans l'appel de fonction. Puis-je créer la structure quelque part avec les valeurs par défaut de ne se soucient pas et définir simplement les champs qui m'intéressent après l'avoir déclarée comme variable locale?
struct toto bar = {.id = 42, .current_route = new_route}; mise à jour (& bar);
Quelle est la manière la plus élégante de transmettre uniquement les informations que je souhaite exprimer à la fonction de mise à jour?
et je veux que tout le reste soit par défaut à -1 (le code secret pour 'ne se soucie pas')
la source
PTHREAD_MUTEX_INITIALIZER
l'utilise également.Vous pouvez changer la valeur spéciale de votre secret à 0 et exploiter la sémantique par défaut des membres de la structure de C.
passera alors 0 comme membres de bar non spécifié dans l'initialiseur.
Ou vous pouvez créer une macro qui effectuera l'initialisation par défaut pour vous:
la source
<stdarg.h>
vous permet de définir des fonctions variadiques (qui acceptent un nombre indéfini d'arguments, commeprintf()
). Je définirais une fonction qui prendrait un nombre arbitraire de paires d'arguments, une qui spécifie la propriété à mettre à jour et une qui spécifie la valeur. Utilisez uneenum
chaîne ou une chaîne pour spécifier le nom de la propriété.la source
enum
variables sur lestruct
terrain? Le coder en dur? Ensuite, cette fonction ne sera applicable qu'à des fichiers spécifiquesstruct
.Envisagez peut-être d'utiliser une définition de macro de préprocesseur à la place:
Si votre instance de (struct foo) est globale, alors vous n'avez pas besoin du paramètre pour cela bien sûr. Mais je suppose que vous avez probablement plus d'une instance. L'utilisation du bloc ({...}) est un GNU-ism qui s'applique à GCC; c'est un moyen agréable (sûr) de garder les lignes ensemble comme un bloc. Si vous devez par la suite ajouter plus aux macros, comme la vérification de la validation de plage, vous n'aurez pas à vous soucier de casser des choses comme les instructions if / else et ainsi de suite.
C'est ce que je ferais, en fonction des exigences que vous avez indiquées. Des situations comme celle-ci sont l'une des raisons pour lesquelles j'ai beaucoup commencé à utiliser python; gérer les paramètres par défaut et cela devient beaucoup plus simple que jamais avec C. (je suppose que c'est un plug python, désolé ;-)
la source
Un modèle utilisé par gobject est une fonction variadique et des valeurs énumérées pour chaque propriété. L'interface ressemble à quelque chose comme:
L'écriture d'une fonction varargs est facile - voir http://www.eskimo.com/~scs/cclass/int/sx11b.html . Faites simplement correspondre les paires clé -> valeur et définissez les attributs de structure appropriés.
la source
Comme il semble que vous n'avez besoin que de cette structure pour la
update()
fonction, n'utilisez pas du tout de structure pour cela, cela ne fera qu'obscurcir votre intention derrière cette construction. Vous devriez peut-être repenser pourquoi vous modifiez et mettez à jour ces champs et définir des fonctions ou des macros distinctes pour ces "petits" changements.par exemple
Ou mieux encore, écrivez une fonction pour chaque cas de changement. Comme vous l'avez déjà remarqué, vous ne modifiez pas toutes les propriétés en même temps, il est donc possible de ne modifier qu'une seule propriété à la fois. Cela améliore non seulement la lisibilité, mais vous aide également à gérer les différents cas, par exemple, vous n'avez pas à vérifier tous les "dont_care" car vous savez que seule la route actuelle est modifiée.
la source
Que diriez-vous de quelque chose comme:
avec:
et:
et en conséquence:
En C ++, un modèle similaire a un nom dont je ne me souviens pas pour le moment.
EDIT : C'est ce qu'on appelle l' idiome du paramètre nommé .
la source
Je suis rouillé avec les structures, donc il me manque probablement quelques mots-clés ici. Mais pourquoi ne pas commencer par une structure globale avec les valeurs par défaut initialisées, la copier dans votre variable locale, puis la modifier?
Un initialiseur comme:
Ensuite, lorsque vous souhaitez l'utiliser:
la source
Vous pouvez résoudre le problème avec une X-Macro
Vous changeriez votre définition de structure en:
Et puis vous seriez en mesure de définir facilement une fonction flexible qui définit tous les champs sur
dont_care
.Suite à la discussion ici , on pourrait également définir une valeur par défaut de cette manière:
Ce qui se traduit par:
Et utilisez-le comme dans la réponse hlovdal , avec l'avantage qu'ici la maintenance est plus facile, c'est-à-dire que la modification du nombre de membres de la structure sera automatiquement mise à jour
foo_DONT_CARE
. Notez que la dernière virgule "fausse" est acceptable .J'ai appris le concept des X-Macros pour la première fois lorsque j'ai dû résoudre ce problème .
Il est extrêmement flexible pour de nouveaux champs ajoutés à la structure. Si vous avez différents types de données, vous pouvez définir des
dont_care
valeurs différentes en fonction du type de données: à partir de là , vous pouvez vous inspirer de la fonction utilisée pour imprimer les valeurs dans le deuxième exemple.Si vous êtes d'accord avec une
int
structure all , vous pouvez omettre le type de données deLIST_OF_foo_MEMBERS
et simplement changer la fonction X de la définition de structure en#define X(name) int name;
la source
X
et généralement ajouter_ENTRY
au nom de la liste, par exemple#define LIST_SOMETHING LIST_SOMETHING_ENTRY(a1, a2, aN) \ LIST_SOMETHING_ENTRY(b1, b2, bN) ...
.Le moyen le plus élégant serait de mettre à jour les champs de structure directement, sans avoir à utiliser la
update()
fonction - mais peut-être qu'il y a de bonnes raisons de l'utiliser qui ne figurent pas dans la question.Ou vous pouvez, comme Pukku l'a suggéré, créer des fonctions d'accès séparées pour chaque champ de la structure.
Sinon, la meilleure solution à laquelle je puisse penser est de traiter une valeur de `` 0 '' dans un champ struct comme un indicateur `` ne pas mettre à jour '' - il vous suffit donc de créer une fonction pour renvoyer une structure remise à zéro, puis de l'utiliser pour mettre à jour.
Cependant, cela peut ne pas être très faisable, si 0 est une valeur valide pour les champs de la structure.
la source