Converting Long -> Hex, then assigning that Hex to a Char in C - c

I am using a function that calculates a 16bit CRC checksum.
The function produces a LONG containing the checksum (base 10 number format). Of course, this can be printed to the console in it's hex equivalent as follows:
printf("Checksum: 0x%x\n", crctablefast((unsigned char *)string, datalength));
For a given 20-byte char array being checked, it would produce the checksum 23277 in Hex format:
Checksum: 5AED
I need to store the check sum as char in the 21st and 22nd places in the char array as the following:
Char [20] = 0x5A
Char [21] = 0xED
The problem is that functions like scanf and sscanf, the best I can do is to assign the characters literally, as follows:
Char [20] = "0x5A"
Char [21] = "0xED"
...which is no good.
What can I do to take two characters at a time, and use those to assign a hex value to a char? Or is there a much easier way in general?
Thank you in advance!

Use bit masks:
ch[20] = (crc >> 8) & 0xff;
ch[21] = crc & 0xff;

It can be saved like this into a character or char array:
Char [20]=(char) 0x5A;
Char [21]=(char) 0xED;
In this way it will save the character equivalent for the integer value of the hex number and you can convert it back by casting and use it.
Well, nothing in the background is in hex, everything in machine is in binary, while human do things in decimal. So, hex is a man machine interface, a representation only.

Related

How to count the characters of a hexadecimal number

since I'm fairly new to C, so this might be a dumb question.
I aimed to use the bitwise operators & to do bit masking.
For example:
If inputs are 0x00F7 and 0x000F,my program should returns 0x0007. However, the output of 0x007&0x000F is just 7, 0x0077&0x00FF is just 77. So is there any way I can count the characters of a hexadecimal number so that I can know how many zeros should I print out?
printf("%X",0x077&0x00FF);
You don't need to count.
You can get printf to pad the number for you, just specify the maximum length like so:
printf("%04X", 0x77 & 0xff);
Note that when you write an integer (no quotes) it makes no difference if you write 0x0077 or 0x77.
Only when you use printf to output a string zeros can be added for visibility.
unsigned char uc = 0x077&0x00FF;
unsigned short us = 0x077&0x00FF;
unsigned int ui = 0x077&0x00FF;
unsigned long long ull = 0x077&0x00FF;
printf("%0*X\n",sizeof(uc)*2, uc);
printf("%0*X\n",sizeof(us)*2, uc);
printf("%0*X\n",sizeof(ui)*2, uc);
printf("%0*X\n",sizeof(ull)*2, uc);
end the output:
77
0077
00000077
0000000000000077

Convert integer char[] to hex char[] avr microcontroller

I'm looking to convert a input variable of this type:
char var[] = "9876543210000"
to a hex equivalent char
char hex[] = "08FB8FD98210"
I can perform this by e.g. the following code::
long long int freq;
char hex[12];
freq = strtoll(var,NULL,10);
sprintf(hex, "%llX",freq);
However I'm doing this on a avr microcontroller, thus strtoll is not available only strtol (avr-libgcc). So I'm restricted to 32 bits integer which is not enough. Any ideas?
Best regards
Simon
Yes.... this method works fine only with positive number, so if you have a minus sign, just save it before doing next. Just divide the string number in two halves, lets say that you select six digit each, to get two decimal numbers: u_int32_t left_part; and u_int32_t right_part; with the two halves of your number.... you can construct your 64 bit number as follows:
u_int64_t number = (u_int64_t) left_part * 1000000 + right_part;
If you have the same problem on the printing side, that is, you cannot print but 32 bit hex numbers, you can just get left_part = number >> 32; and right_part = number & 0xffffffff; and finally print both with:
if (left_part) printf("%x%08x", left_part, right_part);
else printf("%x", right_part);
the test makes result not to be forced to 8 digits when it is less than 0x100000000.
It looks like you might have to parse the input one digit at a time, and save the result into a uint64_t variable.
Initialize the uint64_t result variable to 0. In a loop, multiply the result by 10 and add the next digit converted to an int.
Now to print the number out in hex, you can use sprintf() twice. First print result >> 32 as a long unsigned int, followed by (long unsigned int)result at &hex[4](or 6 or 8 or wherever) to pick up the remaining 32 bits.
You will need to specify the format correctly to get the characters in the array in the correct places. Perhaps, just pad it with 0s? Don't forget about room for the trailing null character.
Change this:
freq = strtoll(var,NULL,10);
To this:
sscanf(var,"%lld",&freq);

using strtol on bytes stored in char array

I'm trying to extract 2nd and 3rd byte from a char array and interpret it's value as an integer. Here in this case, want to extract 0x01 and 0x18 and interpret its value as 0x118 or 280 (decimal) using strtol. But the output act len returns 0.
int main() {
char str[]={0x82,0x01,0x18,0x7d};
char *len_f_str = malloc(10);
int i;
memset(len_f_str,'\0',sizeof(len_f_str));
strncpy(len_f_str,str+1,2);
printf("%x\n",str[1] & 0xff);
printf("%x\n",len_f_str[1] & 0xff);
printf("act len:%ld\n",strtol(len_f_str,NULL,16));
return 0;
}
Output:
bash-3.2$ ./a.out
1
18
act len:0
What am I missing here? Help appreciated.
strtol converts an ASCII representation of a string to a value, not the actual bits.
Try this:
short* myShort;
myShort = (short*) str[1];
long myLong = (long) myShort;
strtol expects the input to be a sequence of characters representing the number in a printable form. To represent 0x118 you would use
char *num = "118";
If you then pass num to strtol, and give it a radix of 16, you would get your 280 back.
If your number is represented as a sequence of bytes, you could use simple math to compute the result:
unsigned char str[]={0x82,0x01,0x18,0x7d};
unsigned int res = str[1] << 8 | str[2];

Unsigned Char pointing to unsigned integer

I don't understand why the following code prints out 7 2 3 0 I expected it to print out 1 9 7 1. Can anyone explain why it is printing 7230?:
unsigned int e = 197127;
unsigned char *f = (char *) &e;
printf("%ld\n", sizeof(e));
printf("%d ", *f);
f++;
printf("%d ", *f);
f++;
printf("%d ", *f);
f++;
printf("%d\n", *f);
Computers work with binary, not decimal, so 197127 is stored as a binary number and not a series of single digits separately in decimal
19712710 = 0003020716 = 0011 0000 0010 0000 01112
Suppose your system uses little endian, 0x00030207 would be stored in memory as 0x07 0x02 0x03 0x00 which is printed out as (7 2 3 0) as expected when you print out each byte
Because with your method you print out the internal representation of the unsigned and not its decimal representation.
Integers or any other data are represented as bytes internally. unsigned char is just another term for "byte" in this context. If you would have represented your integer as decimal inside a string
char E[] = "197127";
and then done an anologous walk throught the bytes, you would have seen the representation of the characters as numbers.
Binary representation of "197127" is "00110000001000000111".
The bytes looks like "00000111" (is 7 decimal), "00000010" (is 2), "0011" (is 3). the rest is 0.
Why did you expect 1 9 7 1? The hex representation of 197127 is 0x00030207, so on a little-endian architecture, the first byte will be 0x07, the second 0x02, the third 0x03, and the fourth 0x00, which is exactly what you're getting.
The value of e as 197127 is not a string representation. It is stored as a 16/32 bit integer (depending on platform). So, in memory, e is allocated, say 4 bytes on the stack, and would be represented as 0x30207 (hex) at that memory location. In binary, it would look like 110000001000000111. Note that the "endian" would actually backwards. See this link account endianess. So, when you point f to &e, you are referencing the 1st byte of the numeric value, If you want to represent a number as a string, you should have
char *e = "197127"
This has to do with the way the integer is stored, more specifically byte ordering. Your system happens to have little-endian byte ordering, i.e. the first byte of a multi byte integer is least significant, while the last byte is most significant.
You can try this:
printf("%d\n", 7 + (2 << 8) + (3 << 16) + (0 << 24));
This will print 197127.
Read more about byte order endianness here.
The byte layout for the unsigned integer 197127 is [0x07, 0x02, 0x03, 0x00], and your code prints the four bytes.
If you want the decimal digits, then you need to break the number down into digits:
int digits[100];
int c = 0;
while(e > 0) { digits[c++] = e % 10; e /= 10; }
while(c > 0) { printf("%u\n", digits[--c]); }
You know the type of int often take place four bytes. That means 197127 is presented as 00000000 00000011 00000010 00000111 in memory. From the result, your memory's address are Little-Endian. Which means, the low-byte 0000111 is allocated at low address, then 00000010 and 00000011, finally 00000000. So when you output f first as int, through type cast you obtain a 7. By f++, f points to 00000010, the output is 2. The rest could be deduced by analogy.
The underlying representation of the number e is in binary and if we convert the value to hex we can see that the value would be(assuming 32 bit unsigned int):
0x00030207
so when you iterate over the contents you are reading byte by byte through the *unsigned char **. Each byte contains two 4 bit hex digits and the byte order endiannes of the number is little endian since the least significant byte(0x07) is first and so in memory the contents are like so:
0x07020300
^ ^ ^ ^- Fourth byte
| | |-Third byte
| |-Second byte
|-First byte
Note that sizeof returns size_t and the correct format specifier is %zu, otherwise you have undefined behavior.
You also need to fix this line:
unsigned char *f = (char *) &e;
to:
unsigned char *f = (unsigned char *) &e;
^^^^^^^^
Because e is an integer value (probably 4 bytes) and not a string (1 byte per character).
To have the result you expect, you should change the declaration and assignment of e for :
unsigned char *e = "197127";
unsigned char *f = e;
Or, convert the integer value to a string (using sprintf()) and have f point to that instead :
char s[1000];
sprintf(s,"%d",e);
unsigned char *f = s;
Or, use mathematical operation to get single digit from your integer and print those out.
Or, ...

How to convert Hex to Ascii in C with and without using sprintf?

I used strtol to convert a string to hex, now I need to print it to the screen. I'm not sure if I can use sprintf since I only have 20k of memory to use on this board. Alternatives welcome.
To do this manually, the easiest way is to have a table mapping nybbles to ASCII:
static const char nybble_chars[] = "0123456789ABCDEF";
Then to convert a byte into 2 hex chars -- assuming unsigned char is the best representation for a byte, but making no assumptions about its size -- extract each nybble and get the char for it:
void get_byte_hex( unsigned char b, char *ch1, char *ch2 ) {
*ch1 = nybble_chars[ ( b >> 4 ) & 0x0F ];
*ch2 = nybble_chars[ b & 0x0F ];
}
This extends straightforwardly to wider data types, and should generate reasonably concise code across a wide range of architectures.
Check out Formatting Codes, if your C implementation supports it, it should be easy to print values in hexadecimal.
Check your C library for ltoa -- the inverse of strtol. Or, write it from scratch (see brone's answer).

Resources