4

I'm trying to "translate" an array of uint8_t [uint8_t lets_try[16]] to a string of 16*8+1[null character] elements. For example:

lets_try[0] = 10101010  
lets_try[1] = 01010101  

...

and I would like to have a string like:

1010101001010101...[\0]

Here the questions: 1) is there a quick way to perform this operation?

I was trying to do it on my own; my idea was starting from translating a single uint8_t variable into a string and obtaining the full array with a loop [I haven't done this last part yet]. At the end I wrote this code:

int main()
{
    uint8_t example = 0x14;
    uint8_t *pointer;
    char *final_string;

    pointer = &example;

    final_string = convert(pointer);
    puts(final_string);

    return(0);
}


char *convert (uint8_t *a)
{
    int buffer1[9];
    char buffer2[9];
    int i;
    char *buffer_pointer;

    buffer1[8]='\0';

    for(i=0; i<=7; i++)
        buffer1[7-i]=( ((*a)>>i)&(0x01) );

    for(i=0; i<=7; i++)
        buffer2[i] = buffer1[i] + '0';

    buffer2[8] = '\0';

    puts(buffer2);

    buffer_pointer = buffer2;

    return buffer_pointer;
}

Here other few questions:

2) I'm not sure I fully understand the magic in this expression I found online: buffer2[i] = buffer1[i] + '0'; can somebody explain to me why the following puts(buffer2) is not going to work correctly without the +'0'? is it the null character at the end of the newborn string which makes the puts() work? [because with the null character it knows it's printing a real string?]

3) in the code above puts(buffer2) gives the right output while the puts in main() gives nothing; I'm going mad in looking again and again the code, I can't find what's wrong with that

4) in my solution I manage to convert an uint8_t into a string passing from an array of int: uint8_t->int array->string; is there a way to shorten this procedure, passing directly from the uint8_t into a string, or improve it? [in forums I found only solutions in C++] it works but I find it a little heavy and not so elegant

Thanks everybody for the support

mch
  • 9,424
  • 2
  • 28
  • 42
Antonino
  • 3,178
  • 3
  • 24
  • 39
  • the function `convert` invokes undefined behaviour, because it returns a local array. You should use `malloc`. – mch Dec 12 '14 at 16:50
  • It's not clear to me what you don't understand...the first loop shifts out the bits of the byte one at a time, but that fills buffer1 with numbers 0 or 1. Adding '0' (which is the number 48--the ASCII value of the character 0) converts them to text. Adding the '\0' (the integer 0) to the end terminates the string so puts() will know where to stop. – Lee Daniel Crocker Dec 12 '14 at 16:50
  • 1
    Isn't `01010101` an octal number literal, and `10101010` a decimal number literal? – Mike Samuel Dec 12 '14 at 17:51

2 Answers2

5

1.) it's a little bit faster to eliminate the int array.

2.) adding '0' changes the integer values 0 and 1 to their ascii values '0' and '1'.

3.) it's undefined behaviour to return the address of a local variable. You have to malloc memory in the heap.

4.) yes, just cut it out and do the whole operation all in one

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

typedef unsigned char uint8_t;

char *convert(uint8_t *a)
{
  char* buffer2;
  int i;

  buffer2 = malloc(9);
  if (!buffer2)
    return NULL;

  buffer2[8] = 0;
  for (i = 0; i <= 7; i++)
    buffer2[7 - i] = (((*a) >> i) & (0x01)) + '0';

  puts(buffer2);

  return buffer2;
}


int main()
{
  uint8_t example = 0x14;
  char *final_string;

  final_string = convert(&example);
  if (final_string)
  {
    puts(final_string);

    free(final_string);
  }
  return 0;
}
mch
  • 9,424
  • 2
  • 28
  • 42
1

Here's one way ...

char *uint8tob( uint8_t value ) {
  static uint8_t base = 2;
  static char buffer[8] = {0};

  int i = 8;
  for( ; i ; --i, value /= base ) {
    buffer[i] = "01"[value % base];
  }

  return &buffer[i+1];
}

char *convert_bytes_to_binary_string( uint8_t *bytes, size_t count ) {
  if ( count < 1 ) {
    return NULL;
  }

  size_t buffer_size = 8 * count + 1;
  char *buffer = calloc( 1, buffer_size );
  if ( buffer == NULL ) {
    return NULL;
  }

  char *output = buffer;
  for ( int i = 0 ; i < count ; i++ ) {
    memcpy( output, uint8tob( bytes[i] ), 8 );
    output += 8;
  }

  return buffer;
};

int main(int argc, const char * argv[]) {
  uint8_t bytes[4] = {  0b10000000, 0b11110000, 0b00001111, 0b11110001 };

  char *string = convert_bytes_to_binary_string( bytes, 4 );
  if ( string == NULL ) {
    printf( "Ooops!\n" );
  } else {
    printf( "Result: %s\n", string );
    free( string );
  }

  return 0;
}

... just extend for 16 bytes. There are many ways and it also depends on what do you mean with quick. Embedded systems, ...? You can make translation table to make it even faster, ...

UPDATE

char *convert_bytes_to_binary_string( uint8_t *bytes, size_t count ) {
  if ( count < 1 ) {
    return NULL;
  }

  const char *table[] = {
    "0000", "0001", "0010", "0011",
    "0100", "0101", "0110", "0111",
    "1000", "1001", "1010", "1011",
    "1100", "1101", "1110", "1111"
  };

  size_t buffer_size = 8 * count + 1;
  char *buffer = malloc( buffer_size );
  if ( buffer == NULL ) {
    return NULL;
  }

  char *output = buffer;
  for ( int i = 0 ; i < count ; i++ ) {
    memcpy( output, table[ bytes[i] >> 4 ], 4 );
    output += 4;
    memcpy( output, table[ bytes[i] & 0x0F ], 4 );
    output += 4;
  }

  *output = 0;

  return buffer;
};

int main(int argc, const char * argv[]) {
  uint8_t bytes[4] = {  0b10000000, 0b11110000, 0b00001111, 0b11110001 };

  char *string = convert_bytes_to_binary_string( bytes, 4 );
  if ( string == NULL ) {
    printf( "Ooops!\n" );
  } else {
    printf( "Result: %s\n", string );
    free( string );
  }

  return 0;
}
zrzka
  • 20,249
  • 5
  • 47
  • 73
  • @mch: your code is so clear, wow! thanks a lot for taking time to improve my code starting from my philosophy/solution; robert: quick meant without the intermediate step; your solution is a pro one, I'll study it carefully because it seems extremely scalable and yeah, I'm working on embedded systems ;) lee: my question was about the meaning of adding '0'. I still had some doubts on returning local variables error and why malloc solves it all but I'm taking a look to the useful: http://stackoverflow.com/questions/12380758/c-error-function-returns-address-of-local-variable ciao! – Antonino Dec 13 '14 at 00:18
  • See my updated answer ... I did optimize it for embedded systems. There's conversion table, also replaced calloc with malloc, no need to zero memory, all bytes will be replaced anyway, also no reference to local buffer, just one malloc, ... – zrzka Dec 14 '14 at 11:34
  • thank you very much again @robert, another beautiful piece of code... have a nice day! – Antonino Dec 16 '14 at 20:51