>10) Thus, int can be replaced by a typedef name defined as int, or the type of argv can be written as
char * * argv, and so on.
And Standard also says that:
>or in some other implementation-defined manner.
and:
>In a freestanding environment (in which C program execution may take place without any
benefit of an operating system), the name and type of the function called at program
startup are implementation-defined.
So main can be pretty much anything according to the Standard, depending on the system.
#include <stdio.h>
int main()
{
float a = 12.5;
printf("%d\n", a);
printf("%d\n", *(int *)&a);
return 0;
}
This program invokes undefined behaviour when it casts float\* to int\*, so technically it could print anything, or do something else. I'm not sure how using memcpy instead would impact the puzzle's point though.
If you know that sizeof(float) >= sizeof(int) the memory alignment should be fine. Also in this case * (int* )&a does not access any bytes outside of an defined data object.
To predict the outcome one have to know the representation of float (IEEE 754) and the big/little endian issues which could be different between floats and ints.
printf("%d\n", a) does promote the value a to a double first
(promotion rules) and then either the first or last part i(assuming sizeof(double) == 2*sizeof(int)) is shown depending on little or big endian architecture.
I have experimented with printf("%d\n", a); using gcc. When compiled for 32-bit x86, it displays the lower 32 bits of the double (which for 12.5 happen to be all 0).
On x86-64, it displays a random value each time, which actually happens to be some pointer (randomised by ASLR). This is because register passing is used on x86-64, and the the double is stored into a floating point register, but %d reads from a different register.
printf("%d\n", * (int*)&a); produces the number 1095237632 for both x86 and x86-64.
Technically, it will print the first N bytes of the float as an int. Where N is the number of bytes ints compile to on the platform. So with knowledge of the platform, the result is entirely predictable.
Only with knowledge of platform AND compiler, though.
Also these are C puzzles and casting pointers to incompatible types and dereferencing them is undefined behavior. Using memcpy would indeed fix this according to e.g. [1].
UB according to the standard has no restrictions, but I think the point of these puzzles is to explain what could reasonably happen on a typical system, and why.
Actually it invokes undefined behavior when it passes a float to printf() and then tries to print it using %d (which of course expects int). Don't do that.
Anyone else spot the uninitialized variable in the banner program?
Also:
> What's the output of the following program. (No, it's not 10!!!)
What's the point of including a program that calls malloc without including a prototype for it, after asking the reader earlier answer why such a program segfaults on IA-64 but not IA-32?
(The answer is: a constraint is violated, requiring a diagnostic, because an int * object pointer is assigned the return value of malloc whose implicit declaration marks it as returning int. The comment issue is a red herring.)
Here's one way, cheating a bit by abusing the definition of "a C program which prints":
A more serious solution, though: