Convert string to bytes array

HI,

I receive a string by serial as: "13ABF2C1"
and I want to convert it to bytes as: byte b[4] = {13, AB, F2, C1}
so that when i rewrite:

for(int i=0; i<4; i++)
{
     serial.print(b[i], HEX);
     serial.print(", ");
}

the output should be: 13, AB, F2, C1,

How I can do this conversion?!
any help appreciated

sscanf?

(BTW, did you remember typing your post in italics?
No, you don't.
Please use code tags when posting code.)

I think using scanf() is often an H-bomb-to-kill-an-ant. It can do a lot of things, but programs often use only a small fraction of its utility, resulting in a program that's bigger than it might be. Try these edits to your code:

byte b[4] = {0x13, 0xAB, 0xF2, 0xC1};    // Make it clear they are hex numbers

void setup() {
  Serial.begin(9600);
  for (int i = 0; i < 4; i++)
  {
    Serial.print(b[i], HEX);             // You need to subscript the array
    Serial.print(", ");
  }
}
void loop() {
}

// You need to subscript the array

It was subscripted, but the forum mangled the [i] into an italics tag.

Agreed, sscanf is overkill, but if it gets you further down the road quicker, why not?
Knowing that it's bloated, you can optimise later if necessary.

 sscanf (string, "%2x%2x%2x%2x", &b [0], &b [1], &b [2], &b [3]);

Is everybody missing the fact he's receiving a string and all he want's to do is insert ", "...

  for(byte i = 0; myString[i]; i++){
    if(i % 2 == 0 && i != 0){
      Serial.print(", ");
    }
    Serial.print(myString[i]);
  }

With myString the received string.

1 Like

Agreed, sscanf is overkill, but if it gets you further down the road quicker, why not?
Knowing that it's bloated, you can optimise later if necessary.

Not sure I agree with you this time. The "why not?" answer is: Teaching shortcuts at the outset usually perpetuates bad coding habits down the road. Besides, I really don't see how it gets you down the road faster. Once you see the mistakes (I did forget about the mangling that the italics did), I thinks it's faster to write it without sscanf(). As to the code size, my version takes 1990 bytes while the sscanf() version takes 3880; almost twice as big. To me, this small rewrite isn't an optimization, it just takes advantage of what's already in place (e.g., defining things correctly and using the Serial object) plus it avoids defining a char array that really isn't needed.

The good news is that the OP can choose for himself. We each demonstrated a tool that he can now hang on his belt...more tools is good. After all, if the only tool you have is a hammer, it's not too surprising that all problems look like a nail.

1 Like

Is everybody missing the fact

I don't think it's a fact until the OP says it's a fact.

econjack, I think you both miss the point of the TS. The printing isn't the problem but "converting" it to the array of bytes. Because he receives a string.

The printing isn't the problem but "converting" it to the array of bytes.

Which is why I presented a means of converting the string into an array, in reply #3.

Your right. But I think that's indeed using a nuclear bomb to kill an ant...

Mr. econjack, (0x13) it works when i enter constant value, but in my case the value is received serialy.
Mr. AWOL, the received string contain extra info also (received string form: Cmd_DEL_13ABF2C1), so is the sscanf still work?!
Mr. septillion, no the printing is not my goal, my goal is the conversion itself because also I need to do a compare it with another bytes array, in addition Mr. septillion, what this (ant) do to kill him with nuclear bomb?!!!

It's a bomb OK, the format specifier should be "%2cx".
Sorry.

Look, guys, I know it's sledgehammer, and if I were chasing the bytes, I'd've coded it as nibble-by-nibble explicit conversion, but I'm trying to get the guy moving.

Yes, sscanf will still work, it just needs a little more work.

1 Like

strtoul, or sscanf as suggested already.

char s[] = "13ABF2C1";
uint8_t b[4];
uint32_t n = strtoul( s, NULL, 16 );

b[0] = ( n >> 24 ) & 0xFF;
b[1] = ( n >> 16 ) & 0xFF;
b[2] = ( n >>  8 ) & 0xFF;
b[3] = ( n & 0xFF );

is the structure of the string always the same? aka, 16 chars? And do you really need to break it up into 3 pieces?

you can do something like:

out = strtol(&myString[8], &pEnd, 16);

Stores it into a long.

If you don't care about the bytes being in the "wrong" order:

char s[] = "13ABF2C1";
uint8_t b[4];
*( uint32_t * )b = strtoul( s, NULL, 16 );

Or:

byte b[4];
char msg[] = "13ABF2C1";

void setup() {
  int i;
  int j;
  char temp[3];
  
  Serial.begin(9600);

  j = 0;
  for (int i = 0; i < 8; i += 2)
  {
    strncpy(temp, &msg[i], 2);
    // Convert 2-character hex string to numeric:
    b[j] = (temp[0] <= '9') ? (temp[0] - '0') : (temp[0] - 'A' + 10);
    b[j] *= 16;
    b[j] += (temp[1] <= '9') ? (temp[1] - '0') : (temp[1] - 'A' +10);

    Serial.print(b[j++], HEX);
    Serial.print(", ");
  }
}
void loop() {
}

which bumps the code size to 2116 vs 3880 for sscanf();

which bumps the code size to 2116 vs 3880 for sscanf();

...but fails if you pass it the perfectly legal "13abf2c1" :wink:

@AWOL: Opps! change to:

byte b[4];
//char msg[] = "13ABF2C1";
char msg[] = "13abf2c1";

void setup() {
  int i;
  int j;
  char temp[3];
  
  Serial.begin(9600);

  j = 0;
  for (int i = 0; i < 8; i += 2)
  {
    msg[i] = toupper(msg[i]);              // To handle upper and lower case...
    strncpy(temp, &msg[i], 2);

    // Convert hex string to numeric:
    b[j] = (temp[0] <= '9') ? (temp[0] - '0') : (temp[0] - 'A' + 10);
    b[j] *= 16;
    b[j] += (temp[1] <= '9') ? (temp[1] - '0') : (temp[1] - 'A' +10);

    Serial.print(b[j++], HEX);
    Serial.print(", ");
  }
}
void loop() {
}

Mr. guix I try your suggestion code in reply #12
it convert the string:"13ABF2C1" to: 00 AB F2 C1
as you see there is a bug in the beginning, why this bug?!
also I see this way is complex, is there simplest way?!

sorry the buy was in my test code!!!
I optimize the function to be as in the reply #20

Mr. econjack, I try your suggestion code in reply #17
the output is: 13, CB, F2, C1,
while the msg was: "13abf2c1"
the 3rd digit is 'a' and convert to 'C'?!!!
Note that, when change the input string to upper case the output became true