How to convert hexadecimal array to decimal and back again in C? - c

I have got a hexadecimal array, which I want to convert to decimal, do a modulus operation, and then convert it back to hexadecimal.
int main()
{
char num[] = {0x02,0x03,0x04};
long n = strtol(num, NULL, 16);
printf("n=%ld\n", n);
}
I am getting "0" here while I am expecting "262914".
EDIT:
I know that putting char num[] = "0x040302" will give me the expected output, but it needs to be withing the {} like {0x02,0x03,0x04}

I know that putting char num[] = "0x040302" will give me the expected
output, but it needs to be withing the {} like {0x02,0x03,0x04}
"0x040302" is the equivalent of { '0', 'x', '0', '4', '0', '3', '0', '2', 0 },
or { 0x30, 0x78, 0x30, 0x34, 0x30, 0x33, 0x30, 0x32, 0x00 } assuming ASCII.

The answer is simply num[0] + (num[1] << 8) + (num[2] << 16). In general, if num is n bytes long, then the answer is:
long i, r = 0;
for (i = 0; i < n; ++i)
{
r += (long)(num[i]) << (8*i);
}
Of course make sure that num fits in a long (generally 4 or 8 bytes depending on your system).

Related

How to split a variable that contains 32 Hex-values into 32 Bytes in C? [duplicate]

how can I convert a hex string to a uint8_t array?
My string is 02012B1530A6E3958A98530031902003876940000000000CDF9844173BE512AFFFFFFE11DBBA1F00079387800E13012E11FC017FFFFFFFFE39C10F40
and I want to convert it into this array:
uint8_t array_uint[] = {0x02, 0x01, 0x2B, 0x15, 0x30, 0xA6, 0xE3, 0x95, 0x8A, 0x98, 0x53, 0x00, 0x31, 0x90, 0x20, 0x03, 0x87, 0x69, 0x40, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xDF, 0x98, 0x44, 0x17, 0x3B, 0xE5, 0x12, 0xAF, 0xFF, 0xFF, 0xFE, 0x11, 0xDB, 0xBA, 0x1F, 0x00, 0x07, 0x93, 0x87, 0x80, 0x0E, 0x13, 0x01, 0x2E, 0x11, 0xFC, 0x01, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x39, 0xC1, 0x0F, 0x40};
Thank you for your help!
You can use sscanf() to convert 2 bytes at a time from the source string into the destination array:
#include <stdint.h>
#include <stdio.h>
size_t convert_hex(uint8_t *dest, size_t count, const char *src) {
size_t i;
int value;
for (i = 0; i < count && sscanf(src + i * 2, "%2x", &value) == 1; i++) {
dest[i] = value;
}
return i;
}
Note however that this approach may be inefficient, with a quadratic time complexity, on architectures where the standard library computes the length of the source string for each call to sscanf(). Using an intermediary array solves this problem:
#include <stdint.h>
#include <stdio.h>
size_t convert_hex(uint8_t *dest, size_t count, const char *src) {
char buf[3];
size_t i;
int value;
for (i = 0; i < count && *src; i++) {
buf[0] = *src++;
buf[1] = '\0';
if (*src) {
buf[1] = *src++;
buf[2] = '\0';
}
if (sscanf(buf, "%x", &value) != 1)
break;
dest[i] = value;
}
return i;
}
Storing the conversion result directly into the dest array is easy:
#include <stdint.h>
#include <stdio.h>
size_t convert_hex(uint8_t *dest, size_t count, const char *src) {
char buf[3];
size_t i;
for (i = 0; i < count && *src; i++) {
buf[0] = *src++;
buf[1] = '\0';
if (*src) {
buf[1] = *src++;
buf[2] = '\0';
}
if (sscanf(buf, "%hhx", &dest[i]) != 1)
break;
}
return i;
}
Purists may argue that %hhx expects a pointer to an unsigned char instead of a uint8_t so the format should be "%"SCNx8 or "%2"SCNx8, defined in <inttypes.h>, but these alternatives are less readable and unnecessary as type uint8_t is always identical to type unsigned char on architectures where it is defined.
The first thing you need to learn is that decimal, hexadecimal or even octal are just how the binary numbers stored in the computer memory are presented. Once you store the bytes in your array, they aren't really hexadecimal anymore.
Now for how to solve your problem: You need to extract two characters at a time, then convert each character to the corresponding integer value, and use bit-shirt and bit-or to combine them into a single byte value.
Converting the digits 0 to 9 into their corresponding value is easy, since the C specification say that they must be encoded contiguously (i.e. '0' must come right before '1' and so on). That means you can use simple subtraction with '0' to get the numeric value ('0' - '0' == 0, '1' - '0' == 1 etc.).
The letters A to F are harder through, because there are many different possible encodings, including some that doesn't place letters contiguously. With that said, the most common encoding ASCII do is doing that, which means on most system you can use the same "trick" as for the decimal digits.
Then how to combine them, the first value needs to be shifted up (to the left) by four bits, and then bitwised OR'ed with the second value.
The result of that should be a single byte whose value is the same as the two hexadecimal digits from the string. Append this value to the array.
With
char data[] = "02012B1530A6E3958A98530031902003876940000000000CDF9844173BE512AFFFFFFE11DBBA1F00079387800E13012E11FC017FFFFFFFFE39C10F40";
char *p = data;
first byte is
(hexdigit(p[0]) << 4) + hexdigit(p[1])
You can loop the above expression with
do {
uint8_t value = (hexdigit(p[0]) << 4) + hexdigit(p[1]);
p += 2;
} while (*p);
for all the values (make sure data has an even number of characters).
The function hexdigit() (implementation is left as an exercise) converts '0' to 0, '1' to 1, ..., 'a' to 10, 'A' to 10, ...

Defining a 128-bit integer in C

To represent this value, I am following the definition:
#define NUM_BITS 128
typedef unsigned char BigInt[NUM_BITS/8];
That is, a value of type BigInt must be represented by an array of bytes, interpreted as a single 128-bit integer, in two's complement and following the little-endian order.
For example, {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, which represents the integer value 1.
I've been thinking of doing a function like that:
void big_val (BigInt res, long val);
Which would be an attribution with extension. The big_val function assigns res the value provided by l (a signed long), correctly extended to 128 bits.
I was thinking of, for example, getting the most significant byte, getting the sign of the number, through y = val & 0xFF000000; and repeat this byte for another 8 times to form my array. But how could I get the bytes which represents the numbers without the signal?
That's what I've done so far:
void big_val(BigInt res, long val){
long y;
y = val&0xFF000000;
for(int i = 8; i < 16; i++){
res[i] = y;
}
}
(To anyone who has seen this post some minutes ago, I accidentally deleted it instead of editing, sorry)
Assign byte by byte, one byte at a time.
void BigInt_init_from_long(BigInt res, long val){
size_t i;
bool negative = val < 0;
for (i = 0; i < sizeof(long); ++i) {
res[i] = val & 0xff;
val >>= 8;
}
for (; i < NUM_BITS/8; ++i) {
res[i] = negative ? 0xff : 0; // sign extension
}
}

How to concatenate the hexadecimal data in an array in C

I have my data field as follows DATA = 0x02 0x01 0x02 0x03 0x04 0x05 0x06 0x07 Now I want to concatenate this data as follows DATA = 0x01020304050607. How can I do it using C program. I found a program in C for concatenation of data in an array and the program is as follows:
#include<stdio.h>
int main(void)
{
int num[3]={1, 2, 3}, n1, n2, new_num;
n1 = num[0] * 100;
n2 = num[1] * 10;
new_num = n1 + n2 + num[2];
printf("%d \n", new_num);
return 0;
}
For the hexadecimal data in the array how can I manipulate the above program to concatenate the hexadecimal data?
You need a 64 bit variable num as result, instead of 10 as factor you need 16, and instead of 100 as factor, you need 256.
But if your data is provided as an array of bytes, then you can simply insert complete bytes, i.e. repeatedly shifting by 8 bits (meaning a factor of 256):
int main(void)
{
uint8_t data[8] = { 0x02, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
unsigned long long num = 0;
for (int i=0; i<8; i++) {
num <<=8; // shift by a complete byte, equal to num *= 256
num |= data[i]; // write the respective byte
}
printf("num is %016llx\n",num);
return 0;
}
Output:
num is 0201020304050607
Lest say you have input like
int DATA[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
If you want output like 0x0001020304050607, to store this resultant output you need one variable of unsigned long long type. For e.g
int main(void) {
int DATA[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
int ele = sizeof(DATA)/sizeof(DATA[0]);
unsigned long long mask = 0x00;
for(int row = 0; row < ele; row++) {
mask = mask << 8;/* every time left shifted by 8(0x01-> 0000 0001) times */
mask = DATA[row] | mask; /* put at correct location */
}
printf("%016llx\n",mask);
return 0;
}
Here's some kind of hack that writes your data directly into an integer, without any bitwise operators:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
uint64_t numberize(const uint8_t from[8]) {
uint64_t r = 0;
uint8_t *p = &r;
#if '01' == 0x4849 // big endian
memcpy(p, from, 8);
#else // little endian
for (int i=7; i >= 0; --i)
*p++ = from[i];
#endif
return r;
}
int main() {
const uint8_t data[8] = { 0x02, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
printf("result is %016llx\n", numberize(data));
return 0;
}
This does work and outputs this independently of the endianness of your machine:
result is 0201020304050607
The compile-time endianness test was taken from this SO answer.

Extra bytes with 2s complement

I'm getting a lot of extra bytes when I find the twos complement of a byte.
for example "eb" turns into "ffffff15". When I printf this, it's -235, not -21 like I would expect it to be.
//unsigned char a[] holds bytes
int b=(int)a[i];
bit1=(b & 0x80 ? 1 : 0);
if (bit1==1){
b=((~b)+1);
}
printf("b: %02x",b);
this prints ffffff15. (%d prints -235).
You did not post the complete code, but it appears a must be an unsigned char array or a unsigned char pointer, or a char array and the type char is unsigned on your platform. Casting a[i] as (int) does not change the value, and evaluates to 235.
The formula b=((~b)+1); does not extend the most significant bit, but merely computes as b = -b. Hence the result -235.
To replicate to most significant bit, you could write:
b = (a[i] & 0xFF) | (-bit1 & ~0xFF);
Here is a complete example:
#include <stdio.h>
int main() {
// a is a byte array
unsigned char a[] = "0a\xeb";
for (size_t i = 0; i < sizeof a; i++) {
int b = (int)a[i];
int s = (b & 0xFF) | ((b & 0x80) ? ~0xFF : 0);
printf("a[%zd] = 0x%hhx, b: 0x%x, %d, s: 0x%x, %d\n",
i, a[i], b, b, s, s);
}
return 0;
}
It prints:
a[0] = 0x30, b: 0x30, 48, s: 0x30, 48
a[1] = 0x61, b: 0x61, 97, s: 0x61, 97
a[2] = 0xeb, b: 0xeb, 235, s: 0xffffffeb, -21
a[3] = 0x0, b: 0x0, 0, s: 0x0, 0
Trying to understand the problem: "eb turns into ffffff15. When I printf this, it's -235, not -21".
So it seems that you expect ffffff15 to represent -21 in decimal, and this seems as if you had a (very common) misunderstanding in how negative integral values are represented: Making a number negative does not just set a single "negative" bit, but actually inverts all the bits (and adds 1). Let's assume an 8 bit example:
1..0000001 -1..11111111
2..0000010 -2..11111110
3..0000011 -3..11111101
...
As you can see, making an integral number int x negative turns it actually into INT_MAX - x + 1 (which is the same as ~x + 1), not into x | 0x800000. In the other way round, 0xfffff15 represents 0xfffffff - 0xeb + 1, which means -235, not -21.

Slice up an uint8_t array

Let's say that I have an array of 16 uint8_t as follows:
uint8_t array[] = {0x13, 0x01, 0x4E, 0x52, 0x31, 0x4A, 0x35, 0x36, 0x4C, 0x11, 0x21, 0xC6, 0x3C, 0x73, 0xC2, 0x41};
This array stores the data contained in a 128 bits register of an external peripheral. Some of the information it represents are stored on 2, 3, 8, 12 bits ... and so on.
What is the best and elegant way to slice it up and bit mask the information I need? (The problem is that some things that I need overlaps the length of one cell of the array)
If that can help, this snippet I wrote converts the whole array into a char* string. But casting this into an int is not option because.. well 16 bytes.
int i;
char str[33];
for(i = 0; i < sizeof(array) / sizeof(*array) ; i++) {
sprintf(str+2*i,"%02hX",array[i]);
}
puts(str);
13014E52314A35364C1121C63C73C241
Actually such problem also occures when trying to parse all kind of bitstreams, like video or image files or compressed data by algorithms like LZ*. So the approach used there is to implement a bitstream reader.
But in your case the bit sequence is fixed length and quite short, so one way is to manually check the field values using bitwise operations.
Or you can use this function that I just wrote, which can extract arbitrary number of bits from a uint8 array, starting from desired bit position:
uint32_t extract_bits(uint8_t *arr, unsigned int bit_index, unsigned int bit_count)
{
/* Assert that we are not requested to extract more than 32 bits */
uint32_t result = 0;
assert(bit_count <= sizeof(result)*8 && arr != NULL);
/* You can additionally check if you are trying to extract bits exceeding the 16 byte range */
assert(bit_index + bit_count <= 16 * 8);
unsigned int arr_id = bit_index / 8;
unsigned int bit_offset = bit_index % 8;
if (bit_offset > 0) {
/* Extract first 'unaligned_bit_count' bits, which happen to be non-byte-aligned.
* When we do extract those bits, the remaining will be byte-aligned so
* we will thread them in different manner.
*/
unsigned int unaligned_bit_count = 8 - bit_offset;
/* Check if we need less than the remaining unaligned bits */
if (bit_count < unaligned_bit_count) {
result = (arr[arr_id] >> bit_offset) & ((1 << bit_count) - 1);
return result;
}
/* We need them all */
result = arr[arr_id] >> bit_offset;
bit_count -= unaligned_bit_count;
/* Move to next byte element */
arr_id++;
}
while (bit_count > 0) {
/* Try to extract up to 8 bits per iteration */
int bits_to_extract = bit_count > 8 ? 8 : bit_count;
if (bits_to_extract < 8) {
result = (result << bits_to_extract) | (arr[arr_id] & ((1 << bits_to_extract)-1));
}else {
result = (result << bits_to_extract) | arr[arr_id];
}
bit_count -= bits_to_extract;
arr_id++;
}
return result;
}
Here is example of how it is used.
uint32_t r;
/* Extracts bits [7..8] and places them as most significant bits of 'r' */
r = extract_bits(arr, 7, 2)
/* Extracts bits [4..35] and places them as most significant bits of 'r' */
r = extract_bits(arr, 4, 32);
/* Visualize */
printf("slice=%x\n", r);
And then the visualisation of r is up to you. They can either be represented as hex dwords, characters, or however you decide.

Resources