Thread: strange typecasting

  1. #1
    Registered User
    Join Date
    May 2009
    Posts
    242

    strange typecasting

    Consider the following code:
    Code:
    #include <stdio.h>
    
    int main()
    {
    	float a = 17.23;
    	int b = *(int*)(&a);
    	printf("Original float formatted as integer is %d\n", a);	// outputs junk, 1893822056 on Linux using gcc
    																// 1073741824 on Windows using Visual Studio 2010
    																
    	printf("Original float formatted as float is %.2f\n", a);	// correct output (17.23)
    	printf("b formatted as integer is %d\n", b);				// outputs junk (different from the corresponding junk for a)
    																// same junk on Windows and Linux, though: 1099552522 
    	printf("b formatted as float is %.2f\n", b);				// outputs 0.00 on Windows and 17.23 on Fedora using gcc
    	return 0;
    }
    This raises several questions for me as to what's actually going on here. So, I'll start with what I think is the simplest one, namely the issue of what is happening with the assignment
    int b = * (int*)(&a);
    My hypothesis is this: The result is junk (but consistent junk) because it results from interpreting the coding of the 4 bytes of memory in which a (a float) is stored as bytes that are instead storing an int.
    Is this hypothesis correct?

    That then brings up the question of how floating point numbers are actually encoded as a binary sequence.

  2. #2
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    My hypothesis is this: The result is junk (but consistent junk) because it results from interpreting the coding of the 4 bytes of memory in which a (a float) is stored as bytes that are instead storing an int.
    It sounds like you have the idea. With the caveat that the code may be horribly broken on some platforms (say, where float is smaller than int, or alignment requirements are different), what you're doing is interpreting the 4 (or whatever) bytes in a float as a 4-byte integer. There is no requirement for this to be meaningful at all, but on many systems it will be.
    That then brings up the question of how floating point numbers are actually encoded as a binary sequence.
    Depends, but the most common floating point type is IEEE 754.

    Note that in your printf() statements, %f expects a double, not a float (you can't pass a float to printf(), because floats are converted to doubles). In any case, systems might pass floating point and integral data differently. What you're doing here is technically undefined behavior, and the output you see will differ from platform to platform. If you want to examine the representation of an object, you can always point an unsigned char* at it and examine byte-by-byte:
    Code:
    #include <stdio.h>
    
    int main(void)
    {
      float a = 17.23;
      unsigned char *p = (unsigned char *)&a;
    
      for(size_t i = 0; i < sizeof a; i++, p++) printf("Byte %02zu: %02x\n", i, *p);
    
      return 0;
    }
    Don't forget that different systems have different byte ordering, too (aka endian-ness).

  3. #3
    Registered User
    Join Date
    May 2009
    Posts
    242
    excellent, tx!

    So, basically, when you give %f an int or %d a float or double in printf(), behavior is undefined; hence the inconsistencies of output.

    Interestingly, in the interim, I calculated out what the binary representation of the 17.23 as float should be according to Computer numbering formats - Wikipedia, the free encyclopedia
    which references ieee 754 and came up with 1099552517 as the integer that should be there (as opposed to 1099552522 in the output). That difference simply has to be either an error in my math on the lower-order bits (not unlikely) or one of the usual inexactnesses that one often sees at large distances from the decimal point.

    I was also wondering about the endian-ness question. If you're following ieee 754, would it in principle matter whether it's big or little endian?

  4. #4
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    came up with 1099552517 as the integer that should be there (as opposed to 1099552522 in the output). That difference simply has to be either an error in my math on the lower-order bits (not unlikely) or one of the usual inexactnesses that one often sees at large distances from the decimal point.
    Essentially, that's right. What's happened is that, because 17.23 is not precisely representable in binary, you have to use an approximation. Yours is just slightly more inaccurate. Print out using a lot of precision (%.10f, say), and see what happens. I get 17.2299995422 and 17.2299900055.
    I was also wondering about the endian-ness question. If you're following ieee 754, would it in principle matter whether it's big or little endian?
    Yes, if you're dealing with the representation. I have code that reads IEEE floats/doubles that have directly been written to a file (using fwrite() or an equivalent). When I read them, I have to be sure that I know what byte order was used or I'll get wildly incorrect values. In general, of course, you needn't worry about byte ordering, because it's transparent to you. But if you're dealing with the actual bytes of an object, it becomes important.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Need help with a strange for-loop problem
    By jasperleeabc in forum C++ Programming
    Replies: 4
    Last Post: 05-29-2009, 08:47 AM
  2. strange number problem
    By kkjj in forum C Programming
    Replies: 9
    Last Post: 08-09-2007, 07:30 AM
  3. strange error -- COM DLL is not installed correctly?
    By George2 in forum C# Programming
    Replies: 0
    Last Post: 07-16-2007, 08:32 AM
  4. Strange results using dnsapi and windns
    By Niara in forum Networking/Device Communication
    Replies: 3
    Last Post: 08-13-2005, 10:21 AM
  5. bcc32 compiling error (really strange!!)
    By jester in forum C++ Programming
    Replies: 14
    Last Post: 01-26-2002, 04:00 PM