4 votes

Comportement mystérieux de sprintf en C : Le deuxième paramètre lld est toujours imprimé comme un zéro (0).

Je rencontre un problème tout à fait bizarre avec sprintf en C qui semble dépasser mes capacités de débogage de base. En gros, j'utilise un simple framework de test unitaire (CuTest) pour ajouter quelques tests à une base de code moche (non documentée, pas de tests unitaires). J'ai ajouté un nouveau type de test unitaire, qui duplique essentiellement ceux qui sont déjà présents, mais pour les entiers 64 bits utilisés dans le code.

Ce test fonctionne en général (il évalue correctement les comparaisons d'égalité), mais lorsqu'il échoue, il ne produit pas le message d'erreur correct en raison du problème de sprintf. La fonction ressemble à ceci :

/* Comparison Function for U64 Numbers */
void CuAssertU64Equals_LineMsg(CuTest* tc, const char* file, int line, const char* message, u64 expected, u64 actual) {
    char buf[STRING_MAX];
    if (expected == actual) return;
    sprintf(buf, "expected <%lld> but was <%lld>", expected, actual);
    CuFail_Line(tc, file, line, message, buf);
}

(Note : STRING_MAX est 512, donc il devrait être assez grand). (Note 2 : Sur le système Cygwin avec lequel je travaille actuellement, un u64 est une variable "long long int").

Lorsque ce test échoue, le message d'erreur produit est la partie la plus étrange. Quelle que soit la valeur de "actual", il imprime 0 à cet endroit. Donc, avec expected = 1 et actual = 2, le message serait le suivant :

"expected <1> but was <0>"

Si vous inversez les positions des arguments, et que vous dites quelque chose comme :

sprintf(buf, "actually <%lld> but expected <%lld>", actual, expected);

Vous obtiendrez le résultat :

"actually <2> but expected <0>"

Inutile de dire que cela n'a pas beaucoup de sens et semble indiquer une sorte d'erreur de pile bizarre peut-être ? Pour être tout à fait honnête, je ne comprends pas du tout comment une telle erreur peut se produire, même en principe. J'ai fait un petit exemple fonctionnel avec le code CuTest et il a fonctionné correctement (je n'ai pas mis le second à zéro). Cela indique que le problème ne vient ni de CuTest, ni de la fonction elle-même.

Cependant, lorsqu'il est utilisé avec la base de code réelle, il rencontre ce problème. Le problème est lié à l'environnement (pile, mémoire ou variables).

Quelqu'un a-t-il une idée de la raison pour laquelle cela se produit ? Mes théories actuelles de candidat sont : 1. Sous-débit ou dépassement de capacité dans la fonction sprintf lors de la lecture des données. Je ne suis pas sûr de la façon dont cela pourrait se produire, puisque toutes les données passées dans la fonction sont par valeur. De plus, les données elles-mêmes existent clairement - je peux voir chaque valeur si je change l'ordre.

  1. Je n'utilise pas le bon formatage. J'étais presque sûr que lld était correct pour un long long int (et fonctionne dans mon exemple minimal de travail) mais peut-être est-ce fragile.

  2. Une sorte de corruption totale de la pile. J'espère que ce n'est pas ça, parce que je ne suis sur ce projet que 20 heures par semaine. Je doute que je puisse déboguer l'ensemble du code de base pour comprendre quelque chose de cette ampleur.

Je compile actuellement avec gcc-3 dans un environnement cygwin, pour ce que ça vaut. Je sais qu'il est impossible d'établir un diagnostic précis sans voir l'ensemble du code, mais même quelques pistes pour déboguer ce genre de problème seraient les bienvenues.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X