HiveBrain v1.2.0
Get Started
← Back to all entries
snippetcMinor

Program to convert binary to hex

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
convertbinaryhexprogram

Problem

I wrote this program to convert binary to hex, it ignores other characters between the binary digits. I would like to receive any recommendations on how to improve it.

#include 
#include 
#include 

const char table[] = "0123456789abcdef";

int main(int argc, char* argv[])
{
  int flip = argc - 2;
  unsigned char* ubin = argv[1];
  unsigned int nibble = 0;
  int i = 0;
  int nothing = 1;

  if((argc != 2) && (argc != 3 || strcmp(argv[2], "-f") != 0)){
    fprintf(stderr, "Usage: %s 00001111 [-f]\n", argv[0]);
    return EXIT_FAILURE;
  }

  printf("%s", "0x");

  while(*ubin){
    if((*ubin != '0') && (*ubin != '1')){
      ++ubin;
      continue;
    }

    nibble <<= 1;
    nibble |= *ubin - '0';

    if(++i == 4){
      i = 0;
      if(flip)
        nibble = ~nibble & 0xf;
      putchar(table[nibble]);
      nibble = 0;
      nothing = 0;
    }

    ++ubin;    
  }

  if(nothing)
    putchar('0');

  putchar('\n');

  if(i)
    fprintf(stderr, "Error: %d bits were discarded, min unit is a nibble\n", i);

  return 0;
}

Solution

#include 
#include 
#include 

const char table[] = "0123456789abcdef";


This constant should be static const char table[]. Just as a general rule, so that it doesn’t conflict with other variables in other files that are also called table.

int main(int argc, char* argv[])
{
  int flip = argc - 2;
  unsigned char* ubin = argv[1];


Using argc and argv before range checking them is dangerous in general. In this case it works, but it means that ubin could be NULL here. This code looks suspicious.

unsigned int nibble = 0;
  int i = 0;


Bad variable name i. It should rather be nbits, since it contains the number of bits in the current nibble.

int nothing = 1;

  if((argc != 2) && (argc != 3 || strcmp(argv[2], "-f") != 0)){
    fprintf(stderr, "Usage: %s 00001111 [-f]\n", argv[0]);
    return EXIT_FAILURE;
  }

  printf("%s", "0x");


A simple printf("0x") would be clearer.

while(*ubin){


Instead of this while loop, write a for loop: for (ubin = argv[1]; *ubin != '\0'; ubin++) {. Then you don’t need to write the ubin++ multiple times.

if((*ubin != '0') && (*ubin != '1')){
      ++ubin;
      continue;
    }

    nibble <<= 1;
    nibble |= *ubin - '0';

    if(++i == 4){
      i = 0;
      if(flip)
        nibble = ~nibble & 0xf;


An alternative would be nibble ^= 0xf;.

putchar(table[nibble]);
      nibble = 0;
      nothing = 0;
    }

    ++ubin;    
  }

  if(nothing)
    putchar('0');

  putchar('\n');

  if(i)
    fprintf(stderr, "Error: %d bits were discarded, min unit is a nibble\n", i);


In case of an error, the return value should be EXIT_FAILURE, not 0.

return 0;
}


But apart from all these comments, the program looks fine. You did the argument checking correctly and strictly. When your program gets more options, you should consider using the getopt library for parsing the command line. But for now, it is fine.

It is unusual to have the options after the remaining arguments; -f 00001111 is more common than 00001111 -f.

The main algorithm is clean and simple. I especially like the error handling at the end. There are too many other programs that just don’t do this.

Code Snippets

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

const char table[] = "0123456789abcdef";
int main(int argc, char* argv[])
{
  int flip = argc - 2;
  unsigned char* ubin = argv[1];
unsigned int nibble = 0;
  int i = 0;
int nothing = 1;

  if((argc != 2) && (argc != 3 || strcmp(argv[2], "-f") != 0)){
    fprintf(stderr, "Usage: %s 00001111 [-f]\n", argv[0]);
    return EXIT_FAILURE;
  }

  printf("%s", "0x");
while(*ubin){

Context

StackExchange Code Review Q#127335, answer score: 4

Revisions (0)

No revisions yet.