Jean
Jean

Reputation: 1857

C : Parse Hex string to unsigned long

I have a string with an IP address :

char *input_string = "fe80000000000000022318fffeedef59";

And I need to convert it to an unsigned long :

unsigned long l = 0xfe80000000000000022318fffeedef59;

I tried a few codes, but none works, here is what I made :

#include <stdio.h>
#include <stdlib.h>
void main() 
{
    char *input_string = "fe80000000000000022318fffeedef59";
    printf("input_string : %s\n\n", input_string);

    unsigned long l1 = strtol(input_string, NULL, 16);
    printf("unsigned long l1 = strtol(input_string, NULL, 16) : l1 = %lx \n\n", l1);

    unsigned long l2 = atol(input_string);
    printf("unsigned long l2 = atol(input_string) : l2 = %lx \n\n", l2);
}

And the output :

input_string : fe80000000000000022318fffeedef59

unsigned long l1 = strtol(input_string, NULL, 16) : l1 = 7fffffffffffffff

unsigned long l2 = atol(input_string) : l2 = 0

Upvotes: 1

Views: 1876

Answers (4)

chux
chux

Reputation: 153338

As @Weather Vane comments: "You'll need a 128-bit numeric variable to hold the value from a 32-byte hex string"

Could use sscanf() to save into 2 64-bit integers.

#include <stdio.h>
#include <stdint.h>
int main(void) {
  uint64_t add[2];
  char *input_string = "fe80000000000000022318fffeedef59";
  if (2 != sscanf(input_string, "%16" SCNx64 "%16" SCNx64, &add[0], &add[1])) {
    return -1;
  }
  printf("%016" PRIx64 "%016" PRIx64 , add[0], add[1]);
  return 0;
}

Upvotes: 1

Jean
Jean

Reputation: 1857

Here is what I have finally done.

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

void big_hex_string_to_long_array(char *);

void main( void)
{
    char *ipv6_string = "FE800000000000000202B3FFFE1E8329";

    big_hex_string_to_long_array(ipv6_string);

}

/*
  * The ipv6 address is 128 bits long, too much to process in a single block.
  * Here I split the address in four equals parts of 32 bits which can be stored
  * in an long int (4 Bytes).
  */
void big_hex_string_to_long_array(char * hex_string)
{
    // create two buffers, one for the most significants bytes and the other for the lowest significants bytes
    char buf_1[8+1];    // +1 : the space for '\0'
    char buf_2[8+1];
    char buf_3[8+1];
    char buf_4[8+1];

    // copy each half in each buffers and add ending character
    memcpy(buf_1, &(*hex_string), sizeof(char)* 8);     // copy the 8 first characters in buf_1
    buf_1[8]='\0';                      // set the last character 
    memcpy(buf_2, &(*hex_string)+8, sizeof(char)* 8);   // copy the 8 next characters in buf_2
    buf_2[8]='\0';                      //...                       
    memcpy(buf_3, &(*hex_string)+16, sizeof(char)* 8);
    buf_3[8]='\0';
    memcpy(buf_4, &(*hex_string)+24, sizeof(char)* 8);
    buf_4[8]='\0';

    printf("\nchar arrays : \nbuf1 = %s\nbuf2 = %s\nbuf3 = %s\nbuf4 = %s\n",buf_1, buf_2, buf_3, buf_4);

    // store each buffer as unsigned long
    long l1 = strtol(buf_1, NULL, 16);      // convert string to long
    long l2 = strtol(buf_2, NULL, 16);
    long l3 = strtol(buf_3, NULL, 16);
    long l4 = strtol(buf_4, NULL, 16);

    printf("\nlong int : \nl1 = %lx\nl2 = %lx\nl3 = %lx\nl4 = %lx\n",l1, l2, l3, l4);
}

Output

char arrays :

buf1 = FE800000

buf2 = 00000000

buf3 = 0202B3FF

buf4 = FE1E8329

long int :

l1 = fffffffffe800000

l2 = 0

l3 = 202b3ff

l4 = fffffffffe1e8329

Upvotes: 0

iqstatic
iqstatic

Reputation: 2382

Your input string (32 byte) corresponds to a very BIG hex number. In order to hold a 32 byte string such as this, you will require a 16 byte (128 bit) data type. But unsigned long is only 8 byte. This is why you are getting such an output.

Upvotes: 3

hipe
hipe

Reputation: 822

Your number is too big for a long. You should check the return status of functions strtol and atol.

Upvotes: 0

Related Questions