# Thread: Decimal to binary tutorial?

1. 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 *p_no_padding;      /* The *_to_bin functions return a pointer to the first
* '1' in the array 'bin_arr' - store that return value
*/

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);
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) {
}
(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;
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;
}
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;
int i = 0;
int *p;
enum {
SET = 1,
NOT_SET = 2
};
int flag = NOT_SET;

while (mask != 0) {
output[i] = 0 + !!(input & mask);
if (flag == NOT_SET && output[i] == 1) {
p = &output[i];
flag = SET;
}
i++;
}

output[i] = -1;
return p;
}

static int *int_to_bin(int output[], unsigned long int input)
{
typedef unsigned int unsigned_integer_t;
int i = 0;
int *p;
enum {
SET = 1,
NOT_SET = 2
};
int flag = NOT_SET;

while (mask != 0) {
output[i] = 0 + !!(input & mask);
if (flag == NOT_SET && output[i] == 1) {
p = &output[i];
flag = SET;
}
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;
int i = 0;
int *p;
enum {
SET = 1,
NOT_SET = 2
};
int flag = NOT_SET;

while (mask != 0) {
output[i] = 0 + !!(input & mask);
if (flag == NOT_SET && output[i] == 1) {
p = &output[i];
flag = SET;
}
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. Originally Posted by CommonTater
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.

3. Originally Posted by quzah
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. 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. Originally Posted by whiteflags
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.

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.

6. Originally Posted by whiteflags
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?)

Popular pages Recent additions