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

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);

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

Using an unsigned int in a do-while loop

I'm new to coding in c and I've been trying to wrap my head around unsigned integers. This is the code I have:
#include <stdio.h>
int main(void)
{
unsigned int hours;
do
{
printf("Number of hours you spend sleeping a day: ");
scanf(" %u", &hours);
}
while(hours < 0);
printf("\nYour number is %u", hours);
}
However, when I run the code and use (-1) it does not ask the question again like it should and prints out (Your number is 4294967295) instead. If I change unsigned int to a normal int, the code works fine. Is there a way I can change my code to make the unsigned int work?
Appreciate any help!
Is there a way I can change my code to make the unsigned int work?
Various approaches possible.
Read as int and then convert to unsigned.
Given "Number of hours you spend sleeping a day: " implies a small legitimate range about 0 to 24, read as int and convert.
int input;
do {
puts("Number of hours you spend sleeping a day:");
if (scanf("%d", &input) != 1) {
Handle_non_text_input(); // TBD code for non-numeric input like "abc"
}
} while (input < 0 || input > 24);
unsigned hours = input;
An unsigned int cannot hold negative numbers. It is useful since it can store a full 32 bit number (twice as large as a regular int), but it cannot hold negative numbers So when you try to read your negative unsigned int, it is being read as a positive number. Although both int and unsigned int are 32 bit numbers, they will be interpreted much differently.
I would try the next test:
do:{
printf("enter valid input...")
scanf("new input...")
} while (hours > 24)
Why should it work?
An unsigned int in C is a binary number, with 32 bit. that means it's max value is 2^32 - 1.
Note that:
2^32 - 1 == 4294967295. That is no coincidence. Negative ints are usually represented using the "Two's complement" method.
A word about that method:
When I use a regular int, it's most significant bit is reserved for sign: 1 if negative, 0 if positive. A positive int than holds a 0 in it's most significant bit, and 1's and 0's on the remaining coordinates in the ordinary binary manner.
Negative ints, are represented differently:
Suppose K is a positive number, represented by N bits.
The number (-K) is represented using 1 in the most significant bit, and the POSITIVE NUMBER: (2^(N-1) - K) occupying the N-1 least significant bits.
Example:
Suppose N = 4, K = 7. Binary representation for 7 using 4 bit:
7 = 0111 (The most significant bit is reserved for sign, remember?)
-7 , on the other hand:
-7 = concat(1, 2^(4-1) - 7) == 1001
Another example:
1 = 0001, -1 = 1111.
Note that if we use 32 bits, -1 is 1...1 (altogether we have 32 1's). This is exactly the binary representation of the unsigned int 4294967295. When you use unsigned int, you instruct the compiler to refer to -1 as a positive number. This is where your unexpected "error" comes from.
Now - If you use the while(hours>24), you rule out most of the illegal input. I am not sure though if you rule out all illegal input. It might be possible to think of a negative number such that the compiler interpret it as a non-negative number in the range [0:24] when asked to ignore the sign, and refer to the most significant bit as 'just another bit'.

32-bits as hex number in C with simple function call

I would like to know if I could get away with using printf to print 32 bits of incoming binary data from a microcontroller as a hexadecimal number. I already have collected the bits into an large integer variable and I'm trying "%x" option in printf but all I seem to get are 8-bit values, although I can't tell if that's a limitation with printf or my microcontroller is actually returning that value.
Here's my code to receive data from the microcontroller:
printf("Receiving...\n");
unsigned int n=0,b=0;
unsigned long lnum=0;
b=iolpt(1); //call to tell micro we want to read 32 bits
for (n=0;n<32;n++){
b=iolpt(1); //read bit one at a time
printf("Bit %d of 32 = %d\n",n,b);
lnum<<1; //shift bits in our big number left by 1 position
lnum+=b; //and add new value
}
printf("\n Data returned: %x\n",lnum); //always returns 8-bits
The iolpt() function always returns the bit read from the microcontroller and the value returned is a 0 or 1.
Is my idea of using %x acceptable for a 32-bit hexadecimal number or should I attempt something like "%lx" instead of "%x" to try to represent long hex even though its documented nowhere or is printf the wrong function for 32-bit hex? If its the wrong function then is there a function I can use that works, or am I forced to break up my long number into four 8-bit numbers first?
printf("Receiving...\n");
iolpt(1); // Tell micro we want to read 32 bits.
/* Is this correct? It looks pretty simple to be
initiating a read. It is the same as the calls
below, iolpt(1), so what makes it different?
Just because it is first?
*/
unsigned long lnum = 0;
for (unsigned n = 0; n < 32; n++)
{
unsigned b = iolpt(1); // Read bits one at a time.
printf("Bit %u of 32 = %u.\n", n, b);
lnum <<= 1; // Shift bits in our big number left by 1 position.
// Note this was changed to "lnum <<= 1" from "lnum << 1".
lnum += b; // And add new value.
}
printf("\n Data returned: %08lx\n", lnum);
/* Use:
0 to request leading zeros (instead of the default spaces).
8 to request a field width of 8.
l to specify long.
x to specify unsigned and hexadecimal.
*/
Fixed:
lnum<<1; to lnum <<= 1;.
%x in final printf to %08lx.
%d in printf in loop to %u, in two places.
Also, cleaned up:
Removed b= in initial b=iolpt(1); since it is unused.
Moved definition of b inside loop to limit its scope.
Moved definition of n into for to limit its scope.
Used proper capitalization and punctuation in comments to improve clarity and aesthetics.
Would something like that work for you?
printf("Receiving...\n");
unsigned int n=0,b=0;
unsigned long lnum=0;
b=iolpt(1); //call to tell micro we want to read 32 bits
for (n=0;n<32;n++){
b=iolpt(1); //read bit one at a time
printf("Bit %d of 32 = %d\n",n,b);
lnum<<1; //shift bits in our big number left by 1 position
lnum+=b; //and add new value
}
printf("\n Data returned: %#010lx\n",lnum); //now returns 32-bit

8 Byte Number as Hex in C

I have given a number, for example n = 10, and I want to calculate its length in hex with big endian and save it in a 8 byte char pointer. In this example I would like to get the following string:
"\x00\x00\x00\x00\x00\x00\x00\x50".
How do I do that automatically in C with for example sprintf?
I am not even able to get "\x50" in a char pointer:
char tmp[1];
sprintf(tmp, "\x%x", 50); // version 1
sprintf(tmp, "\\x%x", 50); // version 2
Version 1 and 2 don't work.
I have given a number, for example n = 10, and I want to calculate its length in hex
Repeatedly divide by 16 to find the number of hexadecimal digits. A do ... while insures the result is 1 when n==0.
int hex_length = 0;
do {
hex_length++;
} while (number /= 16);
save it in a 8 byte char pointer.
C cannot force your system to use 8-byte pointer. So if you system uses 4 byte char pointer, we are out of luck. Let us assume OP's system uses 8-byte pointer. Yet integers may be assigned to pointers. This may or may not result in valid pointer.
assert(sizeof (char*) == 8);
char *char_pointer = n;
printf("%p\n", (void *) char_pointer);
In this example I would like to get the following string: "\x00\x00\x00\x00\x00\x00\x00\x50".
In C, a string includes the various characters up to an including a null character. "\x00\x00\x00\x00\x00\x00\x00\x50" is not a valid C string, yet is a valid string literal. Code cannot construct string literals at run time, that is a part of source code. Further the relationship between n==10 and "\x00...\x00\x50" is unclear. Instead perhaps the goal is to store n into a 8-byte array (big endian).
char buf[8];
for (int i=8; i>=0; i--) {
buf[i] = (char) n;
n /= 256;
}
OP's code certainly will fail as it attempts to store a string which is too small. Further "\x%x" is not valid code as \x begins an invalid escape sequence.
char tmp[1];
sprintf(tmp, "\x%x", 50); // version 1
Just do:
int i;
...
int length = round(ceil(log(i) / log(16)));
This will give you (in length) the number of hexadecimal digits needed to represent i (without 0x of course).
log(i) / log(base) is the log-base of i. The log16 of i gives you the exponent.
To make clear what we're doing here: When rising 16 to the power of the found exponent, we get back i: 16^log16(i) = i.
By rounding up this exponent using ceil(), you get the number of digits.

How to split a 64-bit number into eight 8-bit values?

Is there a simple way to split one 64-bit (unsigned long long) variable into eight int8_t values?
For example:
//1001000100011001100100010001100110010001000110011001000110011111
unsigned long long bigNumber = 10455547548911899039;
int8_t parts[8] = splitULongLong(bigNumber);
parts would be something along the lines of:
[0] 10011111
[1] 10010001
[2] 00011001
...
[7] 10010001
{
uint64_t v= _64bitVariable;
uint8_t i=0,parts[8]={0};
do parts[i++]=v&0xFF; while (v>>=8);
}
First you shouldn't play such games with signed values, this only complicates the issue. Then you shouldn't use unsigned long long directly, but the appropriate fixed width type uint64_t. This may be unsigned long long, but not necessarily.
Any byte (assuming 8 bit) in such an integer you may obtain by shifting and masking the value:
#define byteOf(V, I) (((V) >> (I)*8)&UINT64_C(0xFF))
To initialize your array you would place calls to that macro inside an initializer.
BTW there is no standard "binary" format for integers as you seem to be assuming.
I think if it can be this:
64bit num %8 ,save this result,and then minus the result then divide the result by 8
last save divided num and save (64bit num %8) num, and last you get two 8bit num , and you can use this two num to replace 64bit num 。 but when you need to operate , you may need to operate 8bit num to 64 bit mun
You should be able to use a Union to split the data up without any movement or processing.
This leaves you with the problem of the resulting table being in hte wrong order which can be easily solved with a macro (if you have lots of hard coded values) or a simple "8-x" subscript calculation.
#define rv(ss) = 8 - ss;
union SameSpace {
unsigned long long _64bitVariable;
int8_t _8bit[8];
} samespace;
_64bitVariable = 0x1001000100011001100100010001100110010001000110011001000110011111;
if (_8bit[rv(1)] == 0x10011111) {
printf("\n correct");
}

Resources