2009-11-20 9 views
1

J'ai une fonction, qui a un pointeur sur une structure comme argument. Comment puis-je vérifier dans cette fonction si tous les champs obligatoires de la structure ont été remplis avant un appel de fonction?C - comment vérifier si tous les champs obligatoires d'une structure sont remplis? (méthode la plus élégante)

exemple:

//lib.c 
void f(X_type *x) 
{ 
    ... 
} 

//user.c 
main(){ 
X_type object; 
object.name = "I am X"; 
object.ID = 1; 
... 
f(X_type &object); 
} 
+2

pouvez-vous donner la définition de la structure? – int3

+0

ça n'a pas d'importance - c'est juste une structure – Norma

+0

Comment pouvez-vous dire champ rempli de celui non rempli? Non rempli est zéro/NULL? – qrdl

Répondre

1

assertions d'utilisation (de assert.h) pour vérifier les conditions préalables nécessaires à votre fonction. C'est à vous de définir ce qu'est une valeur valide ou invalide pour un champ de la structure.

exemple:

assert(NULL != object); 
assert(NULL != object->name); 
+1

Cela n'échouera-t-il pas parce que la mémoire n'est pas initialisée? –

+0

Je dois vérifier si une structure a été remplie. – Norma

+0

@Sebastiaan: Vérifier qu'un morceau de mémoire est initialisé ou non est difficile. Je ne vois pas de silverbullet à ce sujet. Les seules choses que je vois faisables sont de vérifier les prérequis. –

0

Votre meilleur pari est d'écrire une fonction qui valide le contenu du struct manuellement et retourne un Vrai/Faux (mais vous le définir), de cette façon vous pouvez facilement utiliser la méthode partout où vous utilisez cette structure.

1

Ajouter un autre membre de la structure pour indiquer si le reste des membres sont remplis (et l'initialiser à « false »). Ensuite, vérifiez simplement ce nouveau membre.

struct whatever { 
    int datagood; 
    /* more members; */ 
}; 

struct whatever bar; 
bar.datagood = 0; 

foo(&bar); /* foo() will see datagood == 0 */ 

/* bar.a = 42; */ 
/* bar.b = 24; */ 
bar.datagood = 1; 

foo(&bar); /* foo() will see datagood == 1 */ 
+0

Qu'est-ce qui peut vous empêcher d'initialiser occasionnellement le seul champ datagood? – okutane

+0

ne ressemble pas à ceci est une interprétation correcte des attentes du problème. mais +1, la suggestion de pmg est bonne pour certaines choses comme l'initialisation paresseuse, comme dans: if (! foo-> InitializedBefore) {/ * ... */foo-> InitializedBefore = 1; } – asveikau

4

Créer une fonction qui prend tous initialiseur les champs comme arguments (comme si elle était un constructeur de l'objet) et l'utiliser au lieu de définir les champs un par un.

Bien sûr, cela n'empêchera personne de le garder dans le mauvais sens, mais si vous maintenez la discipline de l'utilisation de cette fonction, il sera beaucoup plus difficile de laisser un champ non initialisé sans le remarquer. Et si vous modifiez les champs de la structure (et la fonction en conséquence), le compilateur se plaindra des arguments incompatibles partout où vous avez oublié de mettre à jour.

Vous pouvez aller un peu plus loin (mais pas beaucoup plus avec simplement C) en faisant quelques astuces avec le préprocesseur et les inclusions pour appliquer l'encapsulation de données, mais c'est un peu compliqué. Tout livre sur OOP avec C vous aidera avec ce problème, mais je ne sais pas si le gain en vaut la chandelle.

+0

faire quelques trucs avec le préprocesseur et les inclusions pour appliquer l'encapsulation des données --- pouvez-vous s'il vous plaît expliquer? OOP avec C vous aidera avec ce problème --- lequel un s'il vous plaît? Je n'ai pas entendu parler de C et OOP (ou vous voulez dire C++?). – Norma

+0

Je veux parler de C simple, mais ce n'est pas très agréable à faire ... jetez un oeil à la documentation Glib par exemple, ou ce livre http://www.planetpdf.com/codecuts/pdfs/ooc.pdf – fortran

+0

jeter un oeil L'exemple suivant: http://en.wikipedia.org/wiki/Opaque_pointer#C la mauvaise chose avec cette approche est que vous devez utiliser toujours de la mémoire dynamique, mais je pense qu'il y avait un moyen de contourner cette en définissant et en définissant des choses ... laissez-moi jeter un coup d'œil. – fortran

2

Est-ce que valgrind est disponible sur votre système? Si vous exécutez votre programme à travers, il détectera automatiquement l'utilisation des variables non initialisées. Il peut également attraper un certain nombre d'autres problèmes (comme l'utilisation de la mémoire qui a déjà été libérée). Cela ne deviendra pas une fonctionnalité permanente de votre programme, mais c'est très bien pour le débogage.

Je combinerais ceci avec les affirmations mentionnées plus haut et les avertissements de compilateur augmentés. C'est à peu près tout ce que vous pouvez faire - le problème est qu'il n'y a pas de différence entre la mémoire initialisée et non initialisée. Pour la machine, ils ne sont que des valeurs.

1

Je ne pense pas qu'il existe une solution dans C lui-même. Comme d'autres l'ont suggéré, vous pouvez utiliser valgrind, mais c'est une autre histoire. J'ai toujours memset() struct:

memset(&object, 0, sizeof(struct mystruct)); 

ou

struct mystruct *p = calloc(1, sizeof(struct mystruct)); 

Ensuite, vous pouvez vérifier les membres contre 0. Je crois que c'est une bonne habitude.

+0

+1 Je me demandais pendant une minute pourquoi personne ne mentionnait memset() ... – asveikau

1

Par analyse statique. Parasoft C++test a BD-PB-NOTINIT (éviter l'utilisation de données non initialisées) règle de flowanalysis pour cela.

0

Ceci est habituellement résolu par une programmation minutieuse, mais si vous devez être sûr, voici une idée surpuissant:

  • Ajouter une somme de contrôle/champ crc.
  • Ajoutez une fonction de mise à jour des membres qui modifie également le champ de somme de contrôle.
  • Lors de l'utilisation, utilisez une autre fonction pour comparer la somme de contrôle des champs avec celle du champ de somme de contrôle.