C how to convert string of unsigned long long to uint32_t[]? - c

Is there any short code convert a string of unsigned long long to uint32_t[]?
eg, 11767989860 => uint32_t[] {0xaaaa, 0xbbbb}?

Ignoring overflow, this gives you an unsigned long long (which I believe is 64-bit, not 32):
unsigned long long r = 0;
while (*pstr >= '0' && *pstr <= '9') r = r * 10 + (*pstr++ - '0');

You have 11767989860 but in string form, and you want it to break into integer array {0x2,0xBD6D4664}.
You can first convert string to long long, then copy 4 bytes from that long long variable into your integer array.
Below is the sample program
#include<stdio.h>
#include<stdint.h>
int main()
{
unsigned long long ll = 0;
uint32_t arr[2];
char str[]="11767989860";
char *tmpPtr = NULL;
tmpPtr = &ll;
sscanf(str,"%llu",&ll);
printf("ll=%llu",ll);
/*Big endian*/
memcpy(arr,&ll,sizeof(ll));
printf("\n%u %u\n",arr[0],arr[1]);
/*Little endian*/
memcpy(&arr,&tmpPtr[4],sizeof(ll)/2);
memcpy(&arr[1],&tmpPtr[0],sizeof(ll)/2);
printf("\n%u %u\n",arr[0],arr[1]);
return 0;
}

Related

Converting a string of chars into its decimal value then back to its character valus

unsigned long long int power(int base, unsigned int exponent)
{
if (exponent == 0)
return 1;
else
return base * power(base, exponent - 1);
}
I am working on a program where I need to take in a string of 8 characters (e.g. "I want t") then convert this into a long long int in the pack function. I have the pack function working fine.
unsigned long long int pack(char unpack[])
{
/*converting string to long long int here
didn't post code because its large*/
}
After I enter "I want t" I get "Value in Decimal = 5269342824372117620" and then I send the decimal to the unpack function. So I need to convert 5269342824372117620 back into "I want t". I tried bit manipulation which was unsuccessful any help would be greatly appreciated.
void unpack(long long int pack)
{
long long int bin;
char convert[100];
for(int i = 63, j = 0, k = 0; i >= 0; i--,j++)
{
if((pack & (1 << i)) != 0)
bin += power(2,j);
if(j % 8 == 0)
{
convert[k] = (char)bin;
bin = 0;
k++;
j = -1;
}
}
printf("String: %s\n", convert);
}
A simple solution for your problem is to consider the characters in the string to be digits in a large base that encompasses all possible values. For example base64 encoding can convert strings of 8 characters to 48-bit numbers, but you can only use a subset of at most 64 different characters in the source string.
To convert any 8 byte string into a number, you must use a base of at least 256.
Given your extra input, After I enter "I want t" I get "Value in Decimal = 5269342824372117620", and since 5269342824372117620 == 0x492077616e742074, you do indeed use base 256, big-endian order and ASCII encoding for the characters.
Here is a simple portable pack function for this method:
unsigned long long pack(const char *s) {
unsigned long long x = 0;
int i;
for (i = 0; i < 8; i++) {
x = x * 256 + (unsigned char)s[i];
}
return x;
}
The unpack function is easy to derive: compute the remainders of divisions in the reverse order:
char *unpack(char *dest, unsigned long long x) {
/* dest is assumed to have a length of at least 9 */
int i;
for (i = 8; i-- > 0; ) {
s[i] = x % 256;
x = x / 256;
}
s[8] = '\0'; /* set the null terminator */
return s;
}
For a potentially faster but less portable solution, you could use this, but you would get a different conversion on little-endian systems such as current Macs and PCs:
#include <string.h>
unsigned long long pack(const char *s) {
unsigned long long x;
memcpy(&x, s, 8);
return x;
}
char *unpack(char *s, unsigned long long x) {
memcpy(s, &x, 8);
s[8] = '\0';
return s;
}

Decimal to Hex conversion (C) is not working for large numbers

I'm making a C program to convert a decimal into a hexadecimal. My program seems to work fine for smaller numbers like 314156 stored in a long int but larger numbers such as 11806310474565 or 8526495043095935640 always return back 0x7FFFFFFF. How can I deal with or store numbers larger than 2147483647 / 2^32. I've tried using long long and unsigned long long, but those aren't working properly with my code.
code:
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char* argv[] ){
if(argc != 2 ){
printf("Usage: %s requires one parameter\n", argv [0]);
return 1;
}
unsigned long long decimal = atoi(argv[1]);
int count = 0, count2 = 0, value = decimal;
char hex[100];
for( ; value!=0 ; value/=10 )
count++;
unsigned long long q = decimal;
int i = 0, r = 0;
while( q != 0){
q = decimal/16;
r = decimal%16;
printf("%*llu = %*llu * 16 + %*d (%X)\n", count, decimal, count, q, 3, r, r);
hex[i++] = r<10 ? r+48 : r+55;
decimal = q;
}
printf("0x");
for(i-- ; i>=0; i--){
printf("%c",hex[i]);
}
printf("\n");
return 0;
}
I'm using gcc as a compiler.
You want atoll(), not atoi(). Read the documentation.
(Disclosure: I stopped reading your code at atoi.)
I've tried using long long and unsigned long long, but those aren't working properly with my code.
They require a different set of functions. If you use atoi to parse a very large number, you get MAX_INT value instead, explaining 0x7FFFFFFF output.
You need to replace the function by atoll:
unsigned long long decimal = atoll(argv[1]);
Note: Using "magic numbers" here
hex[i++] = r<10 ? r+48 : r+55;
is not ideal. It is better to write
hex[i++] = r<10 ? r+'0' : r+'A'-10;
or even
hex[i++] = "0123456789ABCDEF"[r];
Convert a string to an unsigned long long with strtoull(). #BLUEPIXY. atoll() fails when the result should be > LLONG_MAX.
unsigned long long decimal = strtoull(argv[1], (char **)NULL, 10);
Change type
unsigned long long decimal = ...;
// int value = decimal;
unsigned long long value = decimal;
Code has trouble with input "0". It just prints "0x"
Change
while( q != 0){
...
}
// to
do {
...
} while( q != 0);
--
For clarity, recommend
// hex[i++] = r<10 ? r+48 : r+55;
hex[i++] = r<10 ? r+'0' : r+'A'-10;
// or
hex[i++] = "0123456789ABCDEF"[r];

Is there any alternative to strtoull() function in C?

I need to convert char* to unsigned long long int and there is a function called strtoull() in the C standard library but it takes to much time. I need to quick conversion between char* to unsigned long long int. How can I write my own conversion function which is faster than the standard one?
Shortest/fastest code I can think of right now:
unsigned long long strtoull_simple(const char *s) {
unsigned long long sum = 0;
while (*s) {
sum = sum*10 + (*s++ - '0');
}
return sum;
}
No error checking. Profile to find if it improves performance. YMMV.
After accept: Tried a variation that does the initial calculation as unsigned before continuing on to unsigned long long. Marginal to negative improvements on my 64-bit machine depending on number set. Suspect it will be faster on machines where unsigned long long operations are expensive.
unsigned long long strtoull_simple2(const char *s) {
unsigned sumu = 0;
while (*s) {
sumu = sumu*10 + (*s++ - '0');
if (sumu >= (UINT_MAX-10)/10) break; // Break if next loop may overflow
}
unsigned long long sum = sumu;
while (*s) {
sum = sum*10 + (*s++ - '0');
}
return sum;
}
If code knows the length of the string then the following had some performance improvements (5%)
unsigned long long strtoull_2d(const char *s, unsigned len) {
unsigned sumu = 0;
#define INT_MAX_POWER_10 9
if (len > INT_MAX_POWER_10) {
len = INT_MAX_POWER_10;
}
while (len--) {
sumu = sumu * 10 + (*s++ - '0');
}
unsigned long long sum = sumu;
while (*s) {
sum = sum * 10 + (*s++ - '0');
}
return sum;
}
Conclusion: Improvements (I tried 7) on the simple original solution could yield small incremental speed efficiencies, but they become more and more platform and data set dependent. Suggest that programing talent is better applied to the higher level code improvements.
Answer from #soerium modified to use unsigned long long give better performance than strtoull().
unsigned long long fast_atoull(const char *str)
{
unsigned long long val = 0;
while(*str)
{
val = (val << 1) + (val << 3) + (*(str++) - 48);
}
return val;
}

conversion of BCD to unsigned char

I have a unsigned char array containing the following value : "\x00\x91\x12\x34\x56\x78\x90";
That is number being sent in Hexadecimal format.
Additionally, it is in BCD format : 00 in byte, 91 in another byte (8 bits)
On the other side I require to decode this value as 0091234567890.
I'm using the following code:
unsigned int conver_bcd(char *p,size_t length)
{
unsigned int convert =0;
while (length--)
{
convert = convert * 100 + (*p >> 4) * 10 + (*p & 15);
++p
}
return convert;
}
However, the result which I get is 1430637214.
What I understood was that I'm sending hexadecimal values (\x00\x91\x12\x34\x56\x78\x90) and my bcd conversion is acting upon the decimal values.
Can you please help me so that I can receive the output as 00911234567890 in Char
Regards
Karan
It looks like you are simply overflowing your unsigned int, which is presumably 32 bits on your system. Change:
unsigned int convert =0;
to:
uint64_t convert = 0;
in order to guarantee a 64 bit quantity for convert.
Make sure you add:
#include <stdint.h>
Cast char to unsigned char, then print it with %02x.
#include <stdio.h>
int main(void)
{
char array[] = "\x00\x91\x12\x34\x56\x78\x90";
int size = sizeof(array) - 1;
int i;
for(i = 0; i < size; i++){
printf("%02x", (unsigned char )array[i]);
}
return 0;
}
Change return type to unsigned long long to insure you have a large enough integer.
Change p type to an unsigned type.
Print value with leading zeros.
unsigned long long conver_bcd(const char *p, size_t length) {
const unsigned char *up = (const unsigned char*) p;
unsigned long long convert =0;
while (length--) {
convert = convert * 100 + (*up >> 4) * 10 + (*up & 15);
++up;
}
return convert;
}
const char *p = "\x00\x91\x12\x34\x56\x78\x90";
size_t length = 7;
printf( "%0*llu\n", (int) (length*2), conver_bcd(p, length));
// 00911234567890

Reading a hexadecimal value from a string into a decimal long

I have a string which contains a hexadecimal value:
"29E94B25"
I want to convert this hexadecimal string into an unsigned long using a base of 10. e.g. I want to create an unsigned long with a value of:
703154981
How can I do this type conversion?
You can read this string into an unsigned long with strtoul:
unsigned long n = strtoul("29E94B25", NULL, 16);
You can then print it in base-10 with printf.
There's no such thing as an unsigned long with a base other than 2.
strtoul is what you need
unsigned long x;
x = strtoul("29E94B25", 0, 16);
One could use sscanf for any type converstions.
#include<stdio.h>
main(){
char a[] = "29E94B25";
unsigned long int b;
sscanf(a,"%X",&b);
printf("%ld",b);
}
C#
String hexNumber = "000001ae";
int i = Int32.Parse(hexNumber, NumberStyles.HexNumber);
MessageBox.Show(i); (or Console.Write(i))
C:
int main(void)
{
char s[] = "0D76";
unsigned long x;
x = strtoul(s, 0, 16);
printf("The value represented by the string \"%s\" is\n"
"%lu (decimal)\n" "%#lo (octal)\n" "%#lx (hex)\n",
s, x, x, x);
return 0;
}

Resources