2010-03-15 14 views
3

J'ai une fonction qui traite certaines données et trouve le seuil qui classe les données avec l'erreur la plus faible. Il ressemble à ceci:La fonction C change le comportement selon qu'il y a un appel à printf

void find_threshold(FeatureVal* fvals, sampledata* data, unsigned int num_samples, double* thresh, double* err, int* pol) { 
    //code to calculate minThresh, minErr, minPol omitted 
    printf("minThresh: %f, minErr: %f, minPol: %d\n", minThresh, minErr, minPol); 
    *thresh = minThresh; 
    *err = minErr; 
    *pol = minPol; 
} 

Puis dans mon dossier de test, j'ai ceci:

void test_find_threshold() { 
    //code to set up test data omitted 
    find_threshold(fvals, sdata, 6, &thresh, &err, &pol); 

    printf("Expected 5 got %f\n", thresh); 
    assert(eq(thresh, 5.0)); 
    printf("Expected 1 got %d\n", pol); 
    assert(pol == 1); 
    printf("Expected 0 got %f\n", err); 
    assert(eq(err, 0.0)); 
} 

Cela va et le test passe avec la sortie suivante:

minThresh: 5.000000, minErr: 0.000000, minPol: 1 
Expected 5 got 5.000000 
Expected 1 got 1 
Expected 0 got 0.000000 

Toutefois, si je retire l'appel à printf() de find_threshold, le test échoue soudainement! Commentant l'affirme pour que je puisse voir ce qui est renvoyée, la sortie est:

Expected 5 got -15.000000 
Expected 1 got -1 
Expected 0 got 0.333333 

Je ne peux aucun sens de ce que ce soit.

+2

Le problème peut être dans le code que vous avez omis (// code pour calculer minThresh, minErr, minPol omis) –

+0

Ce que vous avez écrit me semble bon à première vue, donc l'erreur réelle réside probablement dans le code que vous avez omis. Êtes-vous sûr que lorsque vous supprimez l'appel 'printf', le code après qu'il est encore en cours d'exécution? Pouvez-vous exécuter ceci dans un débogueur de niveau source (tel que gdb)? –

+0

Alias ​​de pointeur? – kennytm

Répondre

5

Je soupçonne un problème avec l'accès mémoire/allocation et test avec valgrind

+0

Je l'ai couru à travers valgrind et il m'a informé qu'il y avait quelques variables non-initialisées dans la fonction. J'ai repéré les coupables (une paire de doubles que j'utilisais pour garder des sommes cumulées) et les ai initialisés correctement et maintenant cela fonctionne. Alors maintenant je sais pourquoi mon code donnait les mauvaises réponses - mais je suis toujours mystifié de savoir comment appeler printf pourrait lui donner les bonnes réponses! –

+1

La seule façon que je peux penser pour comprendre cela serait de regarder le code de l'assemblée générée. Avez-vous compilé avec des optimisations? Peut-être que le printf fait des variables allouées sur la pile au lieu d'un registre, et le résultat est différent (probablement par chance puisque les variables ont été unitalisées) –

+0

Le dernier commentaire de David me semble juste puisque l'appel 'printf' va clober les registres, ajoutant cela va changer l'allocation des variables aux registres/mémoire dans la fonction appelante. – caf

6

printf peut appeler malloc. Pour cette raison, si vous avez des pointeurs qui pendent, appeler printf peut modifier les valeurs pointées par ceux-ci. Si votre programme était strictement conforme, vous ne remarqueriez pas ce genre de différences lorsque vous appelez printf (comme vous vous en doutez). Au pire, une allocation dans printf pourrait échouer, mais ne pas corrompre silencieusement d'autres variables.

+0

Pour tester cela, déplacez vos appels 'printf' en dessous de la dernière de vos instructions d'affectation. De cette façon, si 'printf' change quelque chose, cela se produira après que la" partie importante "de la fonction aura lieu. – bta