0

I'm new to C. I was trying to write a script that would take a double and print the IEEE 754 binary representation. I was able to successfully do it with float and int, but I'm not sure why it's not working with double.

Essentially, my code creates a pointer to the location in memory that the double is stored, and then a for loop will & each bit in that pointer with a mask, where but one of the bits are zero. The for loop will go through each bit in the pointer and print the value of & for each bit, which in turn prints the way the double is stored in memory.

At least, in theory. The doubles that are being returned don't match the input.

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

void inputFloat(float n)
{ // start void                                                                                                                                                     
  int *p; // pointer to n                                                                                                                                             
  p = &n;
  int i;
  for (i = 31; i >= 0; i--)
    { // open for loop                                                                                                                                              
      int mask = 1<<i;
      int and = *p & mask;
      if (and == 0) printf("0");
      else printf("1");
    } // close for loop                                                                                                                                             
} //end float void                                                                                                                                                  

void inputInt(int n)
{ // start void                                                                                                                                                     
  int *p; // pointer to n                                                                                                                                             
  p = &n;
  int i;
  for (i = 31; i >= 0; i--)
    { // open for loop                                                                                                                                              
      int mask = 1<<i;
      int and = *p & mask;
      if (and == 0) printf("0");
      else printf("1");
    } // close for loop                                                                                                                                             
} //end int void                                                                                                                                                    
/* new */ 
void inputDouble(double n)
  { // start void                                                                                                                             
    unsigned long long *p; // pointer to n                                                                                                    
    printf("input= %f\n", n);
    p = (unsigned long long *)&n;
 int i;
  for (i = 63; i >= 0; i--)
    { // open for loop                                                                                                                        
      int shift =i;
      unsigned long long mask = 1<<shift;
      unsigned long long and =*p & mask;
                                                                               
                                                                                                               
       if (and == 0) printf("0");                                                                                                           
            else printf("1");                                                                                                               
        } // close for loop     
/* old
void inputDouble(double n)
{ // start void                                                                                                                                                   
  int *p; // pointer to n                                                                                                                                         
  p = &n;
  int i;

  for (i = 63; i >=0; i--)
    { // open for loop                                                                                                                                              
      int mask = 1<<i;
      int and = *p & mask;
      if (and == 0) printf("0");
      else printf("1");
    } // close for loop                                                                                                                                             
} //end double void                                                                                                                                               
*/
int main(int argc, char **argv)
{ // open int main                                                                                                                                                  

  char *pointer;
  double  dub;

  int option;
  while ((option = getopt(argc, argv, "f:i:d:")) !=-1)
    { //open while loop                                                                                                                                             
      switch (option)
        { // open switch                                                                                                                              
          case 'f' :
            inputFloat(atof(optarg));
            printf("\nFloat");
            break; // end float option                                                                                                                                      

          case 'i' :
            inputInt(atoi(optarg));
            printf("\nInteger");
            break;

          case 'd' :
            dub = strtod(optarg, &pointer);
            inputDouble(dub);
            printf("\n Double");
            break;

          default :
            printf("Error");
            break;
        } // end switch                                                                                                                                               
      }//end while loop                                                                                                                                               

    printf("\n");
    return 0;
} // end int main                                                                                                                                                   
  • 3
    You can't use an `int*` to iterate through a `double` (well, not the way you are using it), as `sizeof(double) != sizeof(int)`. Technically same with `float`, but that may "work" if `sizeof(float) == sizeof(int)`. For a `double`, try `long` or `long long` instead of `int`, whichever one has the same size as `double`. But really, you should be using `unsigned char*` instead of integers to iterate through the bytes and bits of arbitrary memory. – Remy Lebeau Oct 08 '20 at 01:27
  • 2
    `double` is 64 bits in your C implementation, but you use a pointer to `int` to access it, and `int` is only 32 bits in your C implementation. Also, the C standard does not define the behavior of accessing objects through incompatible types, with some exceptions. And `1< – Eric Postpischil Oct 08 '20 at 01:28
  • Sorry, I'm having a hard time following, I understand a `double` is a 64 bit number and `int`s are expressed in 32 bit. So can't `int *p;` just need to become `double *p;`instead of `long *p`? I also don't understand why (or how) to change the iteration from `int` to `unsigned char *` Would really appreciate a little more info on that. – Juan Pablo Tolento Oct 08 '20 at 02:15
  • For the "why", look up the "strict aliasing rule". – Nate Eldredge Oct 08 '20 at 02:19
  • If you dereference a pointer to a `double`, then you will get a floating point value. However, this is useless to you, as you want its binary representation. Therefore, you need to have use a pointer to some integer data type. If you don't want to violate the [strict aliasing rule](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule), then this data type should be `char *` (both `signed char` and `unsigned char` is allowed). – Andreas Wenzel Oct 08 '20 at 02:23
  • Ok, I understand why I would would want `long *p;` for my pointer. I've still never heard of iterating `char ` through a loop. How would I go about implementing that for my purposes? Thanks again! – Juan Pablo Tolento Oct 08 '20 at 02:45
  • See [C11 Standard - §6.5 Expressions (p6,7)](http://port70.net/~nsz/c/c11/n1570.html#6.5p6) last bullet point under PP 7. – David C. Rankin Oct 08 '20 at 02:57
  • @JuanPabloTolento: You know that`sizeof(double) == 8` and that `sizeof(unsigned char) == 1`, so you can just write `unsigned char *p = (unsigned char *)&n; for ( int i = 0; i < 8; i++ ) printf( "%02hhX ", *p++ );` – Andreas Wenzel Oct 08 '20 at 03:50
  • @JuanPabloTolento: Note that the code in my previous comment will print a hexadecimal representation of the individual bytes, not a binary representation. However, converting hexadecimal digits to binary digits should not be a problem. – Andreas Wenzel Oct 08 '20 at 04:22
  • the posted code does not cleanly compile! the compiler outputs 3 warning messages about implicit conversions. These problems need to be corrected. When compiling, always enable the warnings, then fix those warnings. (for `gcc`, at a minimum use: `-Wall -Wextra -Wconversion -pedantic -std=gnu11` ) Note: other compilers use different options to produce the same results – user3629249 Oct 08 '20 at 18:22
  • @user3629249 Code has been updated to compile with out warnings in void double. Other voids can be addressed in a similar manner. Note that this fix still does not help print binary representation of doubles. – Juan Pablo Tolento Oct 08 '20 at 21:38
  • 1
    There is essentially a single way to print a binary representation of anything. You set up an `unsigned char*` to point to your object. You interpret it as if it was pointing to the beginning of an array of `unsigned char` of size exactly `sizeof(your_object)`. You inspect and print the binary representation of that array. Anything else is asking for trouble. (There are some minor variations but using e.g. `int*` is not one of those). – n. m. could be an AI Oct 08 '20 at 21:44

0 Answers0