64-Bit Number Conversion Tool
Around 10 years ago I posted about a number conversion tool. Several improvements have made it into the tool in those years, so it's time for an update. The most notable change is the support for 64-bit resolution on the numbers (also when compiled on 32-bit systems). In addition there is support for more operators like and (&), or (|), multiplication (*), division (/) and modulus (%).
Here is the updated code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <limits.h> /* __WORDSIZE */
static uint64_t power_of_two(uint64_t n)
{
if (n == 0)
return 1;
else
return 2 * power_of_two(n - 1);
}
static char *convert_to_bin(uint64_t integer)
{
static char buffer[65]; /* Should not be longer than 64-bits + NULL. */
int i, first_one;
buffer[64] = '\0'; /* Always terminate. */
first_one = 63;
for (i = 63; i >= 0; i--) {
if (integer >= power_of_two(i)) {
buffer[63 - i] = '1';
if (first_one > (63 - i))
{
first_one = (63 - i);
}
integer -= power_of_two(i);
} else {
buffer[63 - i] = '0';
}
}
return &buffer[first_one];
}
static uint64_t convert_from_bin(char *number)
{
uint64_t value;
int n;
char *p;
value = 0;
n = strlen(number) - 3; /* Also minus "0b". */
p = &number[2];
do {
if (*p == '0') {
n--;
} else if (*p == '1') {
value += power_of_two(n);
n--;
}
} while (*p++ != '\0');
return value;
}
static uint64_t convert_to_int(char *number)
{
uint64_t integer;
if (strncmp(number, "0x", 2) == 0) {
integer = strtoull(number, NULL, 16);
} else if (strncmp(number, "0b", 2) == 0) {
integer = convert_from_bin(number);
} else if (strncmp(number, "-", 1) == 0) {
integer = atoll(number); /* Handle signed integers. */
} else {
integer = strtoull(number, NULL, 10);
}
return integer;
}
static uint64_t biggest_int(uint64_t n1, uint64_t n2, uint64_t n3)
{
/* NOTE: Does not handle signed integers, so padding will be off. */
if (n1 > n2 && n1 > n3) {
return n1;
} else if (n2 > n3) {
return n2;
} else {
return n3;
}
}
static void display_int(uint64_t integer, char *prefix, uint64_t biggest)
{
int pad;
if (prefix != NULL)
{
printf("%s", prefix);
}
#if (__WORDSIZE == 64)
pad = snprintf(NULL, 0, "%ld", biggest)
- snprintf(NULL, 0, "%ld", integer);
#else /* __WORDSIZE == 32 */
pad = snprintf(NULL, 0, "%lld", biggest)
- snprintf(NULL, 0, "%lld", integer);
#endif /* __WORDSIZE */
while (pad-- > 0) {
printf(" ");
}
#if (__WORDSIZE == 64)
printf("%ld ", integer);
#else /* __WORDSIZE == 32 */
printf("%lld ", integer);
#endif /* __WORDSIZE */
printf("0x");
#if (__WORDSIZE == 64)
pad = snprintf(NULL, 0, "%lx", biggest)
- snprintf(NULL, 0, "%lx", integer);
#else /* __WORDSIZE == 32 */
pad = snprintf(NULL, 0, "%llx", biggest)
- snprintf(NULL, 0, "%llx", integer);
#endif /* __WORDSIZE */
while (pad-- > 0) {
printf("0");
}
#if (__WORDSIZE == 64)
printf("%lx ", integer);
#else /* __WORDSIZE == 32 */
printf("%llx ", integer);
#endif /* __WORDSIZE */
printf("0b");
pad = strlen(convert_to_bin(biggest))
- strlen(convert_to_bin(integer));
while (pad-- > 0) {
printf("0");
}
printf("%s\n", convert_to_bin(integer));
}
int main(int argc, char *argv[])
{
uint64_t n1, n2, result, biggest;
char *prefix;
if (argc == 2) { /* Just display the number in different forms. */
n1 = convert_to_int(argv[1]);
display_int(n1, NULL, n1);
} else if (argc == 4) { /* Perform extra operation. */
n1 = convert_to_int(argv[1]);
n2 = convert_to_int(argv[3]);
if (argv[2][0] == '+') {
result = n1 + n2;
prefix = " + ";
} else if (argv[2][0] == '-') {
result = n1 - n2;
prefix = " - ";
} else if (argv[2][0] == '^') {
result = n1 ^ n2;
prefix = " ^ ";
} else if (argv[2][0] == '&') {
result = n1 & n2;
prefix = " & ";
} else if (argv[2][0] == '|') {
result = n1 | n2;
prefix = " | ";
} else if (argv[2][0] == '*') {
result = n1 * n2;
prefix = " * ";
} else if (argv[2][0] == '/') {
result = n1 / n2;
prefix = " / ";
} else if (argv[2][0] == '%') {
result = n1 % n2;
prefix = " % ";
} else {
fprintf(stderr, "%s: error: invalid operator.\n", argv[0]);
return -1;
}
biggest = biggest_int(n1, n2, result);
display_int(n1, " ", biggest);
display_int(n2, prefix, biggest);
display_int(result, " = ", biggest);
} else {
fprintf(stderr, "Usage: %s <number> [<operator> <number>]\n", argv[0]);
fprintf(stderr, " number can be integer decimal, hex (0x) or binary (0b)\n");
fprintf(stderr, " valid operators: + - ^ & | * / %%\n");
return -1;
}
return 0;
}