06 February 2012

bug c++ coding tips

Es-ce vraiment important de définir une valeur par défaut pour nos variables dans un corps de fonction ?

Je viens de passer 2 jours à chercher un bug, et cela se résumé simplement à un bête int toto = -1;

Lors que l’on code, on se retrouve souvent avec un paquet de variables déclarées en début d’une fonction. Il peut arriver que ces variables ne soient pas initialisées, et on espère que cela se passera bien ensuite lors de son initialisation.

Mais il y a des cas, ou trouver pourquoi un code ne fonctionne plus est assez difficile lorsque l’on ne prête pas attention à ces bouts lignes, souvent courtes, en surnombre et pouvant être là depuis un paquet de temps.

Donc voici ma petit expérience simple d’un code qui se trouve ne pas fonctionnement correctement suite à un oublie de déclaration de valeur par défaut, de valeurs de retour par souvent bien définit, et du passage d’un mode de compilation debug → normal.

Soit le code suivant :

#define NE_PAS_CONTINUER 0
#define CONTINUER 1

bool lireEnregistrement(int index, TypeEnregistrement *enreg, int *continuer)
{
	bool ret = false;
	ret = lecture_shm_fichier_ou_autre_enregistrement(index, &enreg);

	if(ret == true)
	{
		// tout est ok, on vérifie si nous sommes à la fin des enregistrement
		if(enreg->data == VALEUR_INDIQUANT_LA_FIN)
		{
			continuer = NE_PAS_CONTINUER;
		}
	}

	return ret;
}

Voilà. Simple court, j’ai volontairement simplifié le tout.

Maintenant imaginons que nous utilisons cette fonction comme ceci :

TypeEnregistrement enreg;
int continue;
int cptIdx = 0;
boolean dataOk;

if(dataOk == lireEnregistrement(cptIdx, enreg, continue))
{
	while(dataOk != false && continue != NE_PAS_CONTINUER)
	{
		// utiliser enregistrement, et avancer

		cptIdx++;
		dataOk = lireEnregistrement(cptIdx, enreg, continue);
	}
}

Et boom ! Par leurs pouvoirs combinés : une valeur trop typique (0) pour signifier qui l’on doit arrêter de rechercher des enregistrement, une non initialisation d’une certaine variable, une fonction pas complétement terminée, et une compilation en mode débug, vous casse la baraque.

En effet, en mode debug, certains initialisations sont faites automatiquement. Ici continue = 0 nous allons entrer dans notre fonction, et si elle retourne true (pas d’erreur grave de lecture) nous nous arretons là. En effet la valeur nous signifiant de ne pas lire plus loin étant exactement positionnée à 0 (NE_PAS_CONTINUER) !

Alors qu’il suffit de si peut de chose pour résoudre le problème :

Déjà, dans notre fonciton utilitaire, placer le flag de continuation à CONTINUER dès le départ, ainsi, s’il y a effectivement la possibilité de continuer, il n’y aura pas de problème.

Mais imaginons, que nous ne puissions pas modifier cette fonction. Il suffit de modifier la déclaration de notre variable continue telle que suit : int continue = -1;

Et voilà, un bug très bête, mais gênant qui ne plante même pas, mais qui s’arrête après la première lecture.