Question

J'ai récemment rencontré un cas où je dois comparer deux fichiers (d'or) et prévus pour la vérification des résultats des tests et même si les données écrites à la fois les fichiers étaient les mêmes, les fichiers ne correspond pas.

Le complément d'enquête, je trouve qu'il ya une structure qui contient des nombres entiers et un tableau de caractères de 64 octets, et non tous les octets du tableau de caractères obtenions utilisé dans la plupart des cas et des champs inutilisés à partir du tableau contiennent au hasard données et qui a été à l'origine du décalage.

Cela me a poser la question de savoir s'il est bon d'initialiser le tableau en C / C ++ et, comme cela se fait en Java?

Était-ce utile?

La solution

Il est bon de mémoire / variables initialiser avant de les utiliser - les variables non initialisées sont une grande source de bugs qui sont souvent très difficiles à traquer

.

Initialiser toutes les données est une très bonne idée lors de l'écriture dans un format de fichier: Il conserve le contenu du fichier, ils plus propres sont donc plus faciles à travailler, moins sujettes à des problèmes si quelqu'un essaie de manière incorrecte les données non initialisées « utiliser » ( rappelez-vous, il ne peut pas être votre propre code qui lit les données à l'avenir), et rend les fichiers beaucoup plus compressible.

La seule bonne raison de ne pas les variables avant initialisez les utiliser est dans la performance critique des situations où l'initialisation est techniquement « inutile » et encourt une surcharge importante. Mais dans la plupart des cas les variables ne causera pas d'initialisation un préjudice important (surtout si elles ne sont immédiatement déclarés avant leur utilisation), mais vous permettra d'économiser beaucoup de temps de développement en éliminant une source commune de bogues.

Autres conseils

En utilisant une valeur non définie dans un tableau de résultats dans le comportement non défini. Ainsi, le programme est libre de produire des résultats différents. Cela peut signifier vos fichiers finissent légèrement différents, ou que le programme se bloque, ou le programme formate votre disque dur, ou le programme provoque des démons pour voler le nez de l'utilisateur ( http://catb.org/jargon/html/N/nasal-demons.html )

Cela ne signifie pas que vous devez définir vos valeurs de tableau lorsque vous créez le tableau, mais vous devez vous assurer que vous initialisez une valeur de tableau avant de l'utiliser. Bien sûr, la façon la plus simple d'y parvenir est de le faire lors de la création du tableau.

MyStruct array[10];
printf( "%f", array[2].v ); // POTENTIAL BANG!
array[3].v = 7.0;
...
printf( "%f", array[3].v ); // THIS IS OK.

Ne pas oublier que pour les énormes tableaux de PODs il y a un raccourci agréable pour tous les membres à initialiser zéro

MyPODStruct bigArray[1000] = { 0 };

Je suis fermement en désaccord avec les opinions données que cela est « éliminons une source commune de bugs » ou « ne pas le faire gâchera avec exactitude de votre programme ». Si le programme fonctionne avec des valeurs non initialisées, alors il a un bug et est incorrect. Initialisant les valeurs ne supprime pas ce bogue, souvent parce qu'ils ne disposent toujours pas les valeurs attendues à la première utilisation. Cependant, quand ils contiennent des données aléatoires, le programme est plus susceptible de se bloquer de manière aléatoire à chaque essai. Toujours avoir les mêmes valeurs peuvent donner un comportement plus déterministe et plantage rend le débogage plus facile.

Pour votre question, il est aussi une bonne pratique de sécurité pour remplacer les pièces inutilisées avant qu'elles ne soient écrites dans un fichier, car ils peuvent contenir quelque chose d'une précédente utilisation que vous ne voulez pas être écrit, comme les mots de passe.

Si vous n'initialisez pas les valeurs dans un c ++ tableau, les valeurs pourraient être quelque chose, il serait bon de les mettre à zéro si vous voulez obtenir des résultats prévisibles.

Mais si vous utilisez le tableau de caractères comme une chaîne terminée par null, alors vous devriez être en mesure d'écrire dans un fichier avec la fonction appropriée.

Bien en C ++, il pourrait être préférable d'utiliser une solution plus POO. C'EST À DIRE. vecteurs, chaînes, etc.

Gardez à l'esprit que les tableaux de maintien non initialisées peuvent avoir des avantages tels que la performance.

Il est seulement mauvais lire de tableaux non initialisées. les avoir autour sans jamais la lecture des lieux non initialisées est très bien.

En outre, si votre programme a bug qui fait lire de la place non initialisée dans le tableau, puis « le cacher » en initialisant défensivement tout tableau à valeur connue est pas la solution pour le bogue, et ne peut faire surface plus tard.

On pourrait écrire un grand article sur la différence entre les deux styles, on peut rencontrer des gens qui Initialiser les variables toujours quand les déclarant et les personnes qui les initialisent en cas de besoin. Je partage un grand projet avec quelqu'un qui est dans la première catégorie et je suis maintenant plus definitly du second type. Toujours a apporté des variables d'initialisation des bugs plus subtiles et les problèmes que non et je vais essayer d'expliquer pourquoi, en se rappelant les cas que je trouvais. Premier exemple:

struct NODE Pop(STACK * Stack)
{
  struct NODE node = EMPTY_STACK;

  if(Stack && Stack->stackPointer)
    node = Stack->node[--Stack->stackPointer];

  return node;
}

Ce fut le code écrit par l'autre gars. Cette fonction est la plus chaude fonction dans notre application (vous imaginez un index de texte sur 500 000 000 phrases dans un arbre ternaire, la pile FIFO est utilisée pour gérer la récursivité que nous ne voulons pas utiliser les appels de fonction récursive). C'était typique de son style de programmation en raison de son initialisation systématique des variables. Le problème avec ce code était le memcpy caché de l'initialisation et les deux autres exemplaires des structures (qui btw appels ont été lancés pas memcpy parfois étrange gcc), donc nous avons eu 3 exemplaires + un appel de fonction cachée dans la plus chaude fonction du projet . il Réécriture à

struct NODE Pop(STACK * Stack)
{
  if(Stack && Stack->stackPointer)
    return Stack->node[--Stack->stackPointer];
  return EMPTY_STACK;
}

Une seule copie (et les prestations complémentaires sur SPARC où il fonctionne, la fonction est une fonction de feuille grâce à l'appel à éviter memcpy et n'a pas besoin de construire une nouvelle fenêtre de registre). Ainsi, la fonction était 4 fois plus rapide.

Un autre problème que j'ai trouvé once, mais ne me souviens pas exactement où (donc aucun exemple de code, désolé). Une variable qui a été initialisé lorsque déclarée mais il a été utilisé dans une boucle, avec switch dans un automate à états finis. Le problème de la valeur d'initialisation n'a pas été l'un des états de l'automate et dans certains cas rares l'automate extremly ne fonctionnait pas correctement. En supprimant l'initialiseur, l'avertissement du compilateur émis fait évident que la variable pourrait être utilisée avant qu'il ne soit correctement initialisé. La fixation de l'automate était alors facile. Moralité:. Initialisant une variable défensive peut supprimer un avertissement très utile du compilateur

Conclusion: Initialiser vos variables à bon escient. Le faire est systematicaly rien de plus que de suivre un culte du cargo (mon copain au travail est le pire cargo culter on peut imaginer, il ne l'utilise jamais goto, initialiser toujours une variable, utilisez beaucoup de déclarations statiques (il est savoir plus rapide de vous (il est en fait, même très lent sur SPARC 64 bits), rend toutes les fonctions inline même si elles ont 500 lignes (à l'aide __attribute__((always_inline)) lorsque le compilateur ne veut pas)

D'abord, vous devez initialiser des tableaux, variables, etc. si cela pas gâchera avec exactitude de votre programme.

En second lieu, il semble que dans ce cas particulier, pas initialisant le tableau n'a pas d'incidence sur l'exactitude du programme original. Au lieu de cela, le programme destiné à comparer les fichiers ne sait pas assez sur le format de fichier utilisé pour dire si les fichiers diffèrent d'une manière significative ( « significatif » défini par le premier programme).

Au lieu de se plaindre au sujet du programme original, je fixe le programme de comparaison pour en savoir plus sur le format de fichier en question. Si le format de fichier est bien documenté, alors vous avez une bonne raison de se plaindre.

Je dirais que les bonnes pratiques en C ++ utilise un std :: vector <> au lieu d'un tableau. Ce n'est pas valable pour C, bien sûr.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top