Thread: Decimal to binary tutorial?

  1. #16
    ... kermit's Avatar
    Join Date
    Jan 2003
    Posts
    1,533
    Here is a monstrosity that I wrote years ago:

    Code:
    /* convert_binary.c
     * Sat Aug 20 17:23:52 EDT 2005
     *
     * A program which accepts an unsigned
     * long integer input from the user
     * and then 'converts' the number
     * to a binary output.
     * The default mode is to display
     * the binary number with the least
     * amount of bits necessary to represent
     * the number.  For example, assuming 8 bit
     * chars, the number 8 given as input would
     * be displayed as 00001000
     * Optionally, the user can choose to display
     * the same number in 16 bit, 32 bit, or 64 bit
     * (provided the machine is a 64 bit architecture).
     * As an example, the number 8 displayed as a 16 bit
     * number would be 0000000000001000
     * The extra bits are 'padding' bits.
     * For the default mode, the user can also choose
     * to display only the relevant bits, and not the
     * padding bits.  For example, the number 8 would
     * be displayed as
     * 1000
     */
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <limits.h>
    
    static unsigned int getint(void);
    static unsigned long int get_long_int(void);
    static int *char_to_bin(int output[], unsigned long int input);
    static int *short_to_bin(int output[], unsigned long int input);
    static int *int_to_bin(int output[], unsigned long int input);
    static int *long_to_bin(int output[], unsigned long int input);
    static void fflush_stdin(void);
    
    int main(void)
    {
            enum {
                    ARR_MAX = 100
            };
            int bin_arr[ARR_MAX] = { 2 };
            int i;
            long int number;
            int num_display_bits;
            int chg_default_mode;
            int display_padding_bits;
            int *p_no_padding;      /* The *_to_bin functions return a pointer to the first
                                     * '1' in the array 'bin_arr' - store that return value
                                     * into *p_no_padding
                                     */
    
            printf("\n\t\tDecimal to Binary\n");
            printf("\t\t-----------------\n\n");
            printf("\tThis program accepts an unsigned value\n");
            printf("\tfrom the user, and converts it to either a 8,\n");
            printf("\t16, 32, or 64 bit value (for those who have a 64 \n");
            printf("\tbit machine.)\n\n");
            printf
                ("\tThe default mode is to display the minimum amount of \n");
            printf
                ("\tbits necessary to represent the number.  You may choose \n");
            printf
                ("\tto display the binary output in a different manner.\n\n");
            printf("\tEnter a number to convert to binary output: ");
            (void) fflush(stdout);
            number = get_long_int();
            printf("\tChange from the default mode (Y or N)?: ");
            (void) fflush(stdout);
            chg_default_mode = getchar();
            fflush_stdin();
            if (chg_default_mode == 'Y' || chg_default_mode == 'y') {
                    printf
                        ("\n\tselect the number of bits you wish to display: ");
                    (void) fflush(stdout);
                    do {
                            (void) puts("\n\n\t1.  Display  8 bits (char)");
                            (void) puts("\t2.  Display 16 bits (short)");
                            (void) puts("\t3.  Display 32 bits (int)");
                            (void) puts("\t4.  Display 64 bits (long)");
                            printf("\n\tEnter your selection (1-4) <ENTER>: ");
                            (void) fflush(stdout);
                    } while ((num_display_bits = getint()) < 0 && number > 4);
    
                    switch (num_display_bits) {
                    case 1:
                            char_to_bin(bin_arr, number);
                            break;
                    case 2:
                            short_to_bin(bin_arr, number);
                            break;
                    case 3:
                            int_to_bin(bin_arr, number);
                            break;
                    case 4:
                            long_to_bin(bin_arr, number);
                            break;
                    default:
                            (void) puts("You have problems....");
                            break;
                    }
    
                    /* The following code is used only if the user chooses not to use the
                     * default and display all of the bits, i.e., the user chooses to
                     * use a 8, 16, 32 or 64 bit mode - we obviously will display all
                     * of the padding bits if the user chooses not to go with the default
                     * mode.
                     */
    
                    printf
                        ("\n\tYou entered %ld which would be displayed in binary as: \n\n",
                         number);
                    printf("\t");
                    (void) fflush(stdout);
                    for (i = 0; bin_arr[i] >= 0; i++) {
                            printf("%d", bin_arr[i]);
                    }
                    (void) puts("\n\n");
    
                    return 0;
    
            } else {
    
                    /* The following deals with 'default mode', i.e., the user chose
                     * not to deviate from the default.  What happens then is that the
                     * number the user entered is tested agains the various macros from
                     * limits.h, and then the appropriate function is called accordingly.
                     */
                    if (number < UCHAR_MAX) {
                            p_no_padding = char_to_bin(bin_arr, number);
                    } else if (number < USHRT_MAX) {
                            p_no_padding = short_to_bin(bin_arr, number);
                    } else if (number < UINT_MAX) {
                            p_no_padding = int_to_bin(bin_arr, number);
                    } else {
                            p_no_padding = long_to_bin(bin_arr, number);
                    }
            }
    
            /* Assuming the user decides not to deviate from the default, we then
             * offer the choice to display all of the bits, or only the bits necessary
             * to properly represent the number entered
             */
    
            if (chg_default_mode == 'N' || chg_default_mode == 'n') {
                    printf
                        ("\tWould you like to display all of the available bits\n");
                    printf
                        ("\t(i.e., leading 0's, or 'padding' bits) (Y or N)?: ");
                    fflush(stdout);
                    display_padding_bits = getchar();
                    fflush_stdin();
                    if (display_padding_bits == 'N'
                        || display_padding_bits == 'n') {
                            printf
                                ("\n\tYou entered %ld which would be displayed in binary as: \n\n",
                                 number);
                            printf("\t");
                            (void) fflush(stdout);
                            while (*p_no_padding != -1) {
                                    printf("%d", *p_no_padding);
                                    p_no_padding++;
                            }
                            (void) puts("\n\n");
    
                    } else {
                            printf
                                ("\n\tYou entered %ld which would be displayed in binary as: \n\n",
                                 number);
                            printf("\t");
                            (void) fflush(stdout);
                            for (i = 0; bin_arr[i] >= 0; i++) {
                                    printf("%d", bin_arr[i]);
                            }
                            (void) puts("\n\n");
                    }
    	}
    	return 0;
    }
    
    static unsigned int getint(void)
    {
            enum {
                    BUF_MAX = 15
            };
    
            char buffer[BUF_MAX] = { (char) 0 };
            char *p;
            int number = 0;
    
            if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
                    perror("fgets()");
                    exit(EXIT_FAILURE);
            }
            if ((p = strchr(buffer, '\n')) != NULL) {
                    *p = '\0';
            }
    
            if ((sscanf(buffer, "%d", &number)) != 1) {
                    (void) puts("Error: call to sscanf() failed");
                    exit(EXIT_FAILURE);
            }
    
            return number;
    }
    
    static unsigned long int get_long_int(void)
    {
            enum {
                    BUF_MAX = 15
            };
    
            char buffer[BUF_MAX] = { (char) 0 };
            char *p;
            long int number = 0;
    
            if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
                    perror("fgets()");
                    exit(EXIT_FAILURE);
            }
            if ((p = strchr(buffer, '\n')) != NULL) {
                    *p = '\0';
            }
    
            if ((sscanf(buffer, "%ld", &number)) != 1) {
                    (void) puts("Error: call to sscanf() failed");
                    exit(EXIT_FAILURE);
            }
    
            return number;
    }
    
    /* The *_to_bin functions, as the names suggest, perform
     * the work of 'converting' an unsigned integer into a
     * binary format.  All four of the functions are identical
     * except for the types, which are unsigned char, unsigned
     * short, unsigned int, and unsigned long respectively.  The
     * comments which document the char_to_bin function will serve
     * equally well for the others.  Basically the number the user
     * entered is sent to one of the functions, where it is converted
     * using bitmasks - the resulting 1's and 0's are stored into the array
     * 'output[]' which is also passed to the functions.
     */
    
    static int *char_to_bin(int output[], unsigned long int input)
    {
            typedef unsigned char unsigned_char_t;
            unsigned_char_t mask;
            int i = 0;
            int *p;
            enum {
                    SET = 1,
                    NOT_SET = 2
            };
            int flag = NOT_SET;     /* The 'flag' variable is used to set a switch
                                     * so we can find the first '1' in the 'output[]'
                                     * array.  The reason for the 'flag' is that we
                                     * need to know the position of the first one, so
                                     * so we can assign it to 'p' and then return it
                                     * to the calling function, which will use it to
                                     * print out the binary number with no padding
                                     * bits.
                                     */
    
            mask = -1;              /* all 1 bits     : 1......1     */
            mask /= 2;              /* leading 0      : 01.....1     */
            mask++;                 /* high bit only  : 10.....0     */
    
            while (mask != 0) {
                    output[i] = 0 + !!(input & mask);
                    if (flag == NOT_SET && output[i] == 1) { /* If its the first time we have
                                                              * seen a '1', take note, and then
                                                              * set the flag
                                                              */
                            p = &output[i];
                            flag = SET;
                    }
                    mask >>= 1;
                    i++;
            }
    
            output[i] = -1;
            return p;
    }
    
    
    static int *short_to_bin(int output[], unsigned long int input)
    {
            typedef unsigned short int unsigned_short_integer_t;
            unsigned_short_integer_t mask;
            int i = 0;
            int *p;
            enum {
                    SET = 1,
                    NOT_SET = 2
            };
            int flag = NOT_SET;
    
            mask = -1;
            mask /= 2;
            mask++;
    
            while (mask != 0) {
                    output[i] = 0 + !!(input & mask);
                    if (flag == NOT_SET && output[i] == 1) {
                            p = &output[i];
                            flag = SET;
                    }
                    mask >>= 1;
                    i++;
            }
    
            output[i] = -1;
            return p;
    }
    
    static int *int_to_bin(int output[], unsigned long int input)
    {
            typedef unsigned int unsigned_integer_t;
            unsigned_integer_t mask;
            int i = 0;
            int *p;
            enum {
                    SET = 1,
                    NOT_SET = 2
            };
            int flag = NOT_SET;
    
            mask = -1;
            mask /= 2;
            mask++;
    
            while (mask != 0) {
                    output[i] = 0 + !!(input & mask);
                    if (flag == NOT_SET && output[i] == 1) {
                            p = &output[i];
                            flag = SET;
                    }
                    mask >>= 1;
                    i++;
            }
    
            output[i] = -1;
            return p;
    }
    
    static int *long_to_bin(int output[], unsigned long int input)
    {
            typedef unsigned long int unsigned_long_integer_t;
            unsigned_long_integer_t mask;
            int i = 0;
            int *p;
            enum {
                    SET = 1,
                    NOT_SET = 2
            };
            int flag = NOT_SET;
    
            mask = -1;
            mask /= 2;
            mask++;
    
            while (mask != 0) {
                    output[i] = 0 + !!(input & mask);
                    if (flag == NOT_SET && output[i] == 1) {
                            p = &output[i];
                            flag = SET;
                    }
                    mask >>= 1;
                    i++;
            }
    
            output[i] = -1;
            return p;
    }
    
    static void fflush_stdin(void)
    {
            char junk[80];
            fgets(junk, 80, stdin);
    }
    I never did have the knack for elegant code.

  2. #17
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by CommonTater View Post
    Well, since our OP seems to have vanished...(Solution in 20 lines)
    Code:
    #include <stdio.h>
    
    int main (void)
      { char binary[33] = {0};
        unsigned int number;
        int x = 0;
    
        printf("Enter a number from 0 to 4294967295 : "); /* UINT_MAX */
        scanf("%d", &number); /* <-- %u */
    You probably want to make sure that's unsigned. Otherwise you have to worry about the signed bit.


    Quzah.
    Hope is the first step on the road to disappointment.

  3. #18
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by quzah View Post
    You probably want to make sure that's unsigned. Otherwise you have to worry about the signed bit.
    Quzah.
    Nice catch... amended for future use... although it does produce the right answers...

  4. #19
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,615
    Well if you compiled with all warnings, the compiler would complain. And even though it may produce the right answers, scanf would change the integer when the user types something negative rather than reject the input. That's weird.

  5. #20
    Registered User
    Join Date
    May 2011
    Location
    Around 8.3 light-minutes from the Sun
    Posts
    1,949
    Quote Originally Posted by whiteflags View Post
    Well if you compiled with all warnings, the compiler would complain. And even though it may produce the right answers, scanf would change the integer when the user types something negative rather than reject the input. That's weird.
    My understanding is that if the format specifier doesn't match where you are storing your object the result is undefined, so "weird" would be appropriate here.

    Quote Originally Posted by C99
    7.19.6.2.10
    Unless assignment suppression was indicated by a *, the result of the conversion is placed in the object pointed to by the first argument following the format argument that has not already received a conversion result. If this object does not have an appropriate type, or if the result of the conversion cannot be represented in the object, the behavior is undefined.
    Quote Originally Posted by anduril462 View Post
    Now, please, for the love of all things good and holy, think about what you're doing! Don't just run around willy-nilly, coding like a drunk two-year-old....
    Quote Originally Posted by quzah View Post
    ..... Just don't be surprised when I say you aren't using standard C anymore, and as such,are off in your own little universe that I will completely disregard.
    Warning: Some or all of my posted code may be non-standard and as such should not be used and in no case looked at.

  6. #21
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by whiteflags View Post
    Well if you compiled with all warnings, the compiler would complain. And even though it may produce the right answers, scanf would change the integer when the user types something negative rather than reject the input. That's weird.
    "Negative" is a representation of the status of the highest bit... bit 31 in the case of my example. If you printed out number using %d you'd get a negative number for the higher half of the range of values. But since my code is merely sampling bit 0, and dividing by 2 simply shifts the bit pattern to the right, it makes no difference if the actual number is negative or not... It's only negative until the first /2 is completed.

    It is correct that I should have used %u in the original scanf() and that is corrected here for future...

    But ultimately it doesn't matter... %d and %u both copy a bit pattern to a 4 byte value... and no the compiler had nothing to say about that.

    Bottom line... it works, in about 5% of kermits code space... what's the problem?
    (Or is it just "pick on Tater day" again?)
    Last edited by CommonTater; 08-16-2011 at 06:42 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Binary to Decimal-- Need help
    By Evandb in forum C Programming
    Replies: 5
    Last Post: 05-18-2004, 10:20 AM
  2. binary to decimal ! how?
    By o0o in forum C++ Programming
    Replies: 8
    Last Post: 12-23-2003, 10:31 PM
  3. binary to decimal
    By jk81 in forum C Programming
    Replies: 1
    Last Post: 09-13-2002, 05:20 AM
  4. decimal to binary
    By bugeye in forum C Programming
    Replies: 5
    Last Post: 03-13-2002, 11:50 AM
  5. decimal to binary, decimal to hexadecimal and vice versa
    By Unregistered in forum C++ Programming
    Replies: 9
    Last Post: 12-08-2001, 11:07 PM