views:

129

answers:

2

I have a function that processes some data and finds the threshold that classifies the data with the lowest error. It looks like this:

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;
}

Then in my test file I have this:

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));
}

This runs and the test passes with the following output:

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

However if I remove the call to printf() from find_threshold, suddenly the test fails! Commenting out the asserts so that I can see what gets returned, the output is:

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

I cannot make any sense of this whatsoever.

+4  A: 

I would suspect some problem with memory access / allocation and test with valgrind

David V.
I ran it through valgrind and it informed me that there were some uninitalized variables in the function. I tracked down the culprits (a pair of doubles I was using to keep cumulative sums) and initialized them properly and now it works.So now I know why my code was giving the wrong answers - but I'm still mystified as to how calling printf could make it give the correct answers!
Daniel
The only way I can think of to figure that out would be to look at the assembly code generated. Did you compile with optimisations ? Perhaps the printf makes some variables allocated on the stack instead of a register, and the result is different (probably by luck since the variables were unitialized)
David V.
David's last comment seems right to me - since the `printf` call will clobber registers, adding it will change the allocation of variables to registers/memory in the calling function.
caf
+5  A: 

printf can call malloc. Because of this, if you have some dangling pointers, calling printf can change the values pointed to by these. If your program was strictly conforming you wouldn't observe this kind of differences when calling printf though (as you rightly expect). At worst an allocation in printf could fail, but not silently corrupt other variables.

Pascal Cuoq
To test this, move your `printf` calls down below the last of your assignment statements. That way, if `printf` is changing anything it will happen after the "important part" of the function takes place.
bta