3

I thought that I can do that easily as I was doing similar with

uint8_t array[6] = {0x00, 0x0d, 0x3f, 0xcd, 0x02, 0x5f}

But, it turns out to be, I am not there yet.

Input structure;

char *MAC_ADDR = "\x00\x22\xC7\xFF\xFF\x27";

I want it to be converted into;

char *MAC_ADDR_NEW = "0022C7FFFF27";

Your inputs are highly appreciated.

Sener
  • 335
  • 4
  • 17
  • 2
    Well, this is not really stripping the `\x` – that's only notation for the C compiler. You want to turn a 6-character string into a 12-character string, where each original character is represented by two hex numbers. – M Oehm Feb 28 '21 at 13:29
  • [This question](https://stackoverflow.com/questions/779875/what-function-is-to-replace-a-substring-from-a-string-in-c) explores replacing all substrings in a string, I think you can adapt this to your needs by replacing `\x` with an empty string. – Ahmed Tounsi Feb 28 '21 at 13:29
  • 2
    Where is the memory for the new MAC address allocated? The basic operation is trivial with `snprintf()` called iteratively, or (given that the Ethernet MAC address is always 6 bytes), you can even call it once with 6 explicitly subscripted references to the data in the MAC address (`snprintf(buffer, sizeof(buffer), "%.2X%.2X%.2X%.2X%.2X%.2X", MAC_ADDR[0], MAC_ADDR[1], MAC_ADDR[2], MAC_ADDR[3], MAC_ADDR[4], MAC_ADDR[5]);`). What's the problem? – Jonathan Leffler Feb 28 '21 at 13:38
  • What exactly do you want? Do you have a 6 byte char array to store a MAC address and what to convert it to a string representation of that MAC address? – Werner Henze Feb 28 '21 at 13:38
  • Note that the input MAC address is _not_ a string; it is a byte array. Strings are null-terminated — the example data starts with a null byte and is therefore an empty string. – Jonathan Leffler Feb 28 '21 at 13:39
  • 2
    I note that `uint8_t array[6]` and `char *MAC_ADDR` present different problems. Where plain `char` is a signed type, the `char *` form needs to be masked or cast to avoid problems with negative values (such as `\xFF`). So, in my previous comment, I should have used either `MAC_ADDR[0] & 0xFF` or `(unsigned char)MAC_ADDR[0]` for the arguments passed to `snprintf()`. When the data is already an array of `uint8_t`, such masking or casting is not needed. – Jonathan Leffler Feb 28 '21 at 13:46
  • @MOehm, I didn't know that. Thank you. – Sener Feb 28 '21 at 13:56
  • @JonathanLeffler, I've put your code snippet into an online compiler. I could get an output as I wanted which is good. Thank you. However, I have a small glitch I don't know what it is so though.How do you declare the buffer variable? If I use `char buffer[13];` it works. But, If I use `char *buffer;` I have segmentation fault. – Sener Feb 28 '21 at 14:00
  • Using `char *buffer` begs my original question — where is the memory for the new MAC address allocated. With `char *buffer;`, you've not allocated any memory anywhere for the data — so you get a crash. You _must_ know where the memory is allocated in C. All the time. If you don't know, you get malfunctions and crashes. – Jonathan Leffler Feb 28 '21 at 14:04
  • @JonathanLeffler. Now it makes sense. Yes, I forgot it completely. I should either use `char str[13];` `char *buffer = str;` or `char *buffer;` `buffer = (char*)malloc(13*sizeof(char));` – Sener Feb 28 '21 at 14:21
  • 1
    Both of those are fine — but where I used `sizeof(buffer)`, I assumed `char buffer[13];` (or any larger size of array) because if `buffer` is just a pointer, the value of `sizeof(buffer)` will be 8 bytes (4 bytes on a 32-bit system). – Jonathan Leffler Feb 28 '21 at 14:24

2 Answers2

2

I'm not quite sure what reusable function means. That said, you could do the allocation and conversion with the (non-standard) asprintf function, as follows:

#include <stdio.h>
#include <stdint.h>

int main(void){
  char *MAC_ADDR = "\x00\x22\xC7\xFF\xFF\x27";
  char *MAC_ADDR_NEW;

  asprintf (&MAC_ADDR_NEW, "%02x%02x%02x%02x%02x%02x",
     (uint8_t)MAC_ADDR[0], (uint8_t)MAC_ADDR[1], (uint8_t)MAC_ADDR[2],
     (uint8_t)MAC_ADDR[3], (uint8_t)MAC_ADDR[4], (uint8_t)MAC_ADDR[5]);
  printf("%s\n", MAC_ADDR_NEW);
  free(MAC_ADDR_NEW); /* Good software hygiene is to free what you allocate. */

  /* You could reuse the same code again here for another conversion. */
  return 0;
}

The casts to uint8_t avoid sign extension for 0xFF values to FFFFFFFF, etc. Error checking left as an exercise.

$ cc x.c && ./a.out
0022c7ffff27
Jens
  • 69,818
  • 15
  • 125
  • 179
  • That will do Jens, thank you. Could you please elaborate `free(MAC_ADDR_NEW);`? It sound like there is `malloc` and we use `free` afterwards. Is it the case here? I meant, the `asprintf` I don't want the variable is cleared out as I want it to live as long as the application runs. – Sener Feb 28 '21 at 14:10
  • 1
    @Sener Yes, asprintf returns in a malloc'ed pointer in the location of the first argument. Do you have manual pages on your system? Then `man asprintf` has the details. Don't call asprintf with the same pointer without a free() in between. That would be a memory leak. – Jens Feb 28 '21 at 14:19
  • Ah, it is good that you mentioned this. I am a bit trying to avoid malloc's as I can forget to free things. I am going to weigh pros and cons between asprintf and snprintf (also well proposed by @Jonathan Leffler. Thank you again. – Sener Feb 28 '21 at 14:29
1

For completeness based on valuable inputs from @Jonathan Leffler and @Jens, I drop my proven answer.

Here is the function I've tested and started to use;

#include <stdio.h>

const unsigned char * MAC_HEX_TO_STR(char *MAC_ADDR);

const unsigned char * MAC_HEX_TO_STR(char *MAC_ADDR){
    // If static is not used, due to local variable is destroyed out of the function will return gibberish!
    static char memory[13]; 
    static char *MAC_ADDR_NEW = memory;   
    snprintf(memory, sizeof(memory), "%.2X%.2X%.2X%.2X%.2X%.2X",  (unsigned char)MAC_ADDR[0],  (unsigned char)MAC_ADDR[1],  (unsigned char)MAC_ADDR[2],  (unsigned char)MAC_ADDR[3],  (unsigned char)MAC_ADDR[4],  (unsigned char)MAC_ADDR[5]);    
    //printf(" 1 ==>>  %s\n  ", MAC_ADDR_NEW); // Debug if you like
    //MAC_ADDR_NEW[13] = 0;  // I don't know, I tried with or without but no difference observed!
    return MAC_ADDR_NEW; 
}      
int main()
{
    char *MAC_ADDR = "\x00\x22\xC7\xFF\xFF\x27";
    const unsigned char* RETURNED_MAC = MAC_HEX_TO_STR(MAC_ADDR);
    printf(" RETURNED_MAC ==>>  %s\n  ", RETURNED_MAC );

    return 0;
}

You may reach the test from here.

Sener
  • 335
  • 4
  • 17