tags:

views:

102

answers:

5

This code, when compiled in xlC 8.0 (on AIX 5.3), produces the wrong result. It should print 12345, but instead prints 804399880. Removing the const in front of result makes the code work correctly.

Where is the bug?

#include <stdio.h>
#include <stdlib.h>
#include <string>

long int foo(std::string input)
{
        return strtol(input.c_str(), NULL, 0);
}

void bar()
{
        const long int result = foo("12345");
        printf("%u\n", result);
}

int
main()
{
        bar();
        return 0;
}

Compilation command:

/usr/vacpp/bin/xlC example.cpp -g

Edit: Changing the printf format string above to "%ld\n" doesn't help. Edit 2: The AIX version used was 5.3, not 6.1.

+3  A: 

xlC 10.0 works fine, seems to be a compiler bug

vasya
Confirmed to also work in VC++ 2005
KevenK
Yes, it also works for me in xlC v10.1.
UdiM
A: 

Probably not related, but be careful: the %u specifier for printf indicates an unsigned integer, but you are passing a signed integer.

MadKeithV
A: 

g++ handles this just fine and doesn't mention a warning. It does complain about printf. You should be using %lu for a long int. Or even better, using %ld or casting to (unsigned long int).

clahey
`%ld` actually.
Georg Fritzsche
Or just use iostream and avoid the whole issue.
Fred Larson
Yeah, %ld would be better, but g++ is fine with %lu. It doesn't care that the number is interpreted wrong, just that it's the right length.
clahey
+2  A: 

This is tagged c++, so what happens when you use cout instead of printf?

It looks like the problem is you're telling printf to print an unsigned int and then sending it a signed long int to actually print. Most likely the memory layout is different and printf can't understand what you actually wanted to do.

Mark B
+1  A: 

It's going to be a bit of a guess why the const matters, but one can make a reasonable assumption.

Variables with block scope, such as result can be allocated to a register or put on the stack. There are many factors that influence whether a register is used. It's quite possible that const matters, in this case. In the end, it's the compilers right to use what it thinks works best.

Similarly, arguments to functions can be passed in registers or on the stack. As functions are often compiled seperately, their interface (i.e. declaration) dictates which argument goes where. printf(...) is a special case, as it can be called with different types arguments. As a result, what data ends up where will vary, and you need to tell printf(...) what to expect.

Now when passing a variable to a function, the compiler usually has to copy it. From a register to the stack, one register to another, etcetera, there are quite a few variations possible. As I indicated, the source location may differ depending on the presence or absence of const.

Now as it happens you pass the wrong format specifier to printf(...), namely %u instead of %ld. This can cause printf(...) to look in the wrong place to get its data - perhaps in a register instead of the stack, or the other way around. Such an action can cause quite surprising results. printf(...) could for instance stumble across your uncopied result, or the random old values in some register. It seems that in the non-const case it happens to find the correct value (even though it might have found it in the wrong place), whereas in the const case printf(...) just finds garbage.

MSalters
Thanks, but the code is 32-bit so "%u" and "%ld" are of the same size.
UdiM