integer promotion in varargs calls
Question: what does this do?
printf("%ld\n", 32);
You might think it prints 32. But I think the results are in fact undefined, and on a 64-bit platform you might get some value other than 32.
The problem is that vprintf (or some function inside it) will try to read off the varargs stack a value of type long, which is 64 bits on ia64 and (all?) other Linux 64-bit platforms. However, the value is a literal integer, and passed as such.
So why does this normally work? I think the reason is that on IA64, all integers are passed in 64-bit slots, with the first 8 parameteres in the frame input registers and the rest on the stack. However, there is no guarantee that the entire slot will be initialized if it's only carrying an int. At least in some cases, gcc generates a st4 instruction to store the value, so the top 32 bits are uninitialized. It seems that they often happen to be zero, but not always. This was causing a semi-intermittent failure of the Vstr test case.
You might think that all integer types are promoted to long, but that is not in fact the case. ISO/IEC 9899:1999 (E), the C specification says basically that types smaller than int are promoted to ints, and floats are promoted to doubles. There is no automatvic promotion to longs.
The correct way to write it, assuming you wanted to pass it as a long, is
printf("%ld\n", 32L);
The good news is that gcc can generally give compile-time warnings for this kind of problem, although it cannot trap every possible case, and it can't trap non-printf varargs functions.
posted Mon 15 Dec 2003 in /software/languages/C | link
Archives 2008: Apr Feb 2007: Jul May Feb Jan 2006: Dec Nov Oct Sep Aug Jul Jun Jan 2005: Sep Aug Jul Jun May Apr Mar Feb Jan 2004: Dec Nov Oct Sep Aug Jul Jun May Apr Mar Feb Jan 2003: Dec Nov Oct Sep Aug Jul Jun May
Copyright (C) 1999-2007 Martin Pool.