0

I just found a solution that convert a string of mac address to a array like below:

#include <stdio.h>
int main()
{

char mac[] = "ff-13-a9-1f-b0-88";

unsigned char a[6];

sscanf(mac, "%x-%x-%x-%x-%x-%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]);

printf("%x,%x", *a, *(a+1));

}

This piece of code works ok and fits my needs. But what if I want to convert a long string like ff-13-a9-1f-b0-88...(REPEAT 100 TIMES)...-ff-00 to char array?

Repeatedly write %x-%x in code is neither convenient nor elegant.

I do consider to use memcpy with a loop, but I just cannot copy half a byte(convert 0x0f, 0x0f to 0xff), right?

Sunil Garg
  • 14,608
  • 25
  • 132
  • 189
Michael
  • 1,313
  • 11
  • 25
  • Although it may appear to work, the code shown has a number of problems. The most important is that there is a buffer overflow of the array because an unsigned int is being written to each entry of the unsigned char array. Also, it would only appear to work on little endian machines and would cause a misaligned write error on some processors. `sscanf(mac, "%x-%x-%x-%x-%x-%x", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]);` should be: `sscanf(mac, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &a[0], &a[1], &a[2], &a[3], &a[4], &a[5]);` – Dipstick May 24 '18 at 15:34

2 Answers2

1

Read one by one, and use %n at the end to get the count of characters consumed so far. I.e.

char *position = mac;
char separator;
int consumed = 0;

while (1) {
    int converted = sscanf(position, "%x%c%n", &one_number, &separator, &consumed);
    if (converted == 2) {
        if (separator == '-') {
            position += consumed;
        }
        else {
            // malformed string, separator wasn't -
        }
    }
    else if (converted == 1) {
        // last number
    }
    else {
        // none converted, scanf error. 
    }
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

You don't need memcpy, you can assign the values to build up the byte like this.

byte_value = lower_nibble + (higher_nibble<<4);

You use the lower_nibble as is, but shift the higher_nibble 4 places so that it becomes 0xf0 (or whatever value it is).

Used in a loop, you can shift the current byte value and then add on the current nibble (half-byte) and then reset it when you hit a non-hex digit

unsigned int byte_value=0;
char *pos
for(pos=mac;*pos!='\0';pos++)
  {
  if(isdigit(*pos))
    {
    byte_value <<= 4;
    byte_value += *pos-'0';
    }
  else if(isxdigit(*pos))
    {
    byte_value <<= 4;
    byte_value += tolower(*pos)-'a'+10;
    }
  else
    {
    printf("Byte is %x\n",byte_value);
    byte_value=0;
    }
  }
printf("Byte is %x\n",byte_value);
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
Chris Turner
  • 8,082
  • 1
  • 14
  • 18