Casting Long to Unsigned Short Int / Strtol - c

There is no compile error. However, the results are not expected. My suspicion is that the casting long to unsigned short int is causing the error. How can I safely cast long to a short for Hex?
[Requiriments: Convert a row of string (which has numbers) to unsigned short int] Thanks!
unsigned short int str_to_bin (char* instr_bin_str) {
unsigned short int i = 0;
long j;
char* ptr;
j = strtol (instr_bin_str, &ptr, 10);
if (j == 0) {
fprintf (stderr, "error6: str_to_bin() failed");
return 6;
}
i = (unsigned short) j;
printf("State: 0x%X \n", i);
return i;
}

The string you're passing in is the binary representation of a number. However, when you're calling strtol you pass in 10 for the third parameter, which means it expects a string in decimal representation.
If you're expecting binary, you need to tell strtol to expect that:
j = strtol (instr_bin_str, &ptr, 2);

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

string to long, not giving me the correct answer

I am trying to convert number stored in the c string to long int. But I am not getting the expected output:
char str[] = "987654321012345";
long int num ;
num = 0;
//num = atol(str);
num = strtol(str, (char **) NULL, 10);
printf("%ld", num);
Output : 821493369
gcc version 4.4.7 20120313 (Red Hat 4.4.7-16)
Can you please advise what am I doing wrong here? Thanks.
In addition to using long long, you can use exact width types from stdint.h. For instance, to guarantee and 64-bit signed number you can use the int64_t type. Regardless what you do, do not cast NULL to char ** and always validate your conversions. E.g.,
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main (void) {
char str[] = "987654321012345";
long num = 0;
errno = 0;
num = strtol (str, NULL, 10);
if (errno) { /* validate strtol conversion */
perror ("strtol conversion failed.");
return 1;
}
printf ("%ld\n", num);
return 0;
}
Example Use/Output
$ ./bin/strtoltst
987654321012345
There are additional error checks you can do on the conversion, but at minimum, make sure errno is not set following your call to strtol or strtoll.
If you would like to use the guaranteed width types, then you can make the following changes:
...
#include <stdint.h>
...
int64_t num = 0;
...
num = strtoll (str, NULL, 10);
The result is the same.
I could reproduce and fix.
Code reproducing the problem
#include <stdio.h>
//#include <stdlib.h>
int main()
{
char str[] = "987654321012345";
long int num ;
char *ix;
num = 0;
//num = atol(str);
num = strtol(str, &ix, 10);
printf("%ld\n", num);
printf("%lu\n", sizeof(long));
return 0;
}
Gives as expected:
821493369
8
After a compilation warning
warning: implicit declaration of strtoll
Reason: as strtoll is undeclared, it is assumed to return an int, so the long value is first truncate to an int and than promoted back to a long.
Fix: just uncomment the #include <stdlib.h> line...
Conclusion: warnings are not meant to be ignored!
You should use long long as datatype for your number.
char str[] = "987654321012345";
long long num = strtoll(str, (char **)NULL, 10);
printf("%lld", num);
According to the C data type:
Long signed integer type. Capable of containing at least the [−2,147,483,647, +2,147,483,647] range; thus, it is at least 32 bits in size.
Long unsigned integer type. Capable of containing at least the [0, 4,294,967,295] range;
Is not enough, so you need a long long or unsigned long long and use %lli or %llu
"987654321012345" is too large.
Strol is outputing long type variable.
Long value is –2,147,483,648 to 2,147,483,647.
try
char str[] = "987654321012345";
char *pEnd;
long long num;
num = 0;
num = strtoull(str,&pEnd, 10);
printf("%lld", num);
return 0;
long long instead of long
strtoull instead of strtol
%lld instead of %ld

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

char* decimal to hexadecimal in little-endian

I have an issue where I am inputting an decimal argument to my code:
./a.out 650
and would like to simply convert the decimal value into hex and output it in a little-endian format:
0A28
My current solution has been to convert the char* to decimal using atoi (we can assume the input is decimal, no worry about error cases).
I have read that I could create an int* and cast it to the char*, something like this:
char* bar = argv[1];
int* foo = (char*)&bar;
and that iterating through it would produce the solution I needed, but I do not quite understand how that would work.
Like this:
#include <stdio.h>
#include <stdlib.h>
unsigned long int n = strtoul(argv[1], NULL, 0);
unsigned char const * p = (unsigned char const *)&n;
for (size_t i = 0; i != sizeof n; ++i)
printf("%02X", p[i]);
To print the reverse endianness, use sizeof n - i - 1 in place of i.
This should take the program's first parameter and print it out as a big endian hexadecimal number and little endian hexadecimal.
int main(int argc, char *argv[]) {
if (argc != 2) return -1;
char *endptr;
unsigned long d = strtoul(argv[1], &endptr, 10);
if (*endptr) {
printf("Not a decimal number '%s'\n", argv[1]);
return 1;
}
printf("%lX\n", d); // normal
do {
printf("%02hhX", (unsigned char) d); // little endian first
d >>= 8;
} while (d);
printf("\n");
return 0;
}

Problem with big numbers in C

why should a code like this should provide a so high result when I give it the number 4293974227 (or higher)
int main (int argc, char *argv[])
{
unsigned long long int i;
unsigned long long int z = atoi(argv[1]);
unsigned long long int tmp1 = z;
unsigned long long int *numbers = malloc (sizeof (unsigned long long int) * 1000);
for (i=0; tmp1<=tmp1+1000; i++, tmp1++) {
numbers[i] = tmp1;
printf("\n%llu - %llu", numbers[i], tmp1);
}
}
Result should start with the provided number but starts like this:
18446744073708558547 - 18446744073708558547
18446744073708558548 - 18446744073708558548
18446744073708558549 - 18446744073708558549
18446744073708558550 - 18446744073708558550
18446744073708558551 - 18446744073708558551
ecc...
What's this crap??
Thanks!
atoi() returns int. If you need larger numbers, try strtol(), strtoll(), or their relatives.
atoi() returns (int), and can't deal with (long long). Try atoll(), or failing that atol() (the former is preferred).
You are printing signed integers as unsigned.

Resources