32-bit and 64-bit return values in OS X
I've spent a couple of days with a dummy compiler problem. I have to admit that it was my fault but, at least, I learned something in the process. To make a long story short: do not forget to include header files and enable all warnings (-Wall).
In C, you can use a function without including its header file. Then, depending on how you set the compilers flags, it might not complain as long as it can find the function at linking time.
Imagine you have this function (defined in foo.h and implemented in foo.c) :
uint64_t foo_add (void);
and you use it in a program bar.c without including the foo.h header:
#include <stdint.h> #include <stdio.h> int main (int argc, char *argv[]) { printf ("%d\n", foo_add ()); return 0; }
(yes, printf will complain in this case because of type mismatches, just imagine printf is something else).
If we disassemble the code of our program we get:
$ otool -tV bar bar.o: (__TEXT,__text) section _main: ... 0000000000000006 callq _foo_add ... 0000000000000012 movl %eax, %esi ... 000000000000001e ret
Now, let's try to include the header foo.h and disassemble again:
$ otool -tV bar bar.o: (__TEXT,__text) section _main: ... 0000000000000004 callq _foo_add ... 0000000000000010 movq %rax, %rsi ... 000000000000001d ret
Note how the compiler uses two different instructions: movl (32-bit) in the first case, when it really doesn't know anything about the foo_add function, and movq (64-bit) when it knows that foo_add returns a 64-bit value.
This can lead to unexpected behavior as I have found in the code I was working on. And actually, I have only found this in OS X.
So, please do not forget to include header files and enable -Wall. It will save you from some headaches.