Hex to int

Hi

I have a little problem with converting my hex to int, long etc.

I have these values examples.

EC3 should be 3779

FDDF = -545

F4AC = -2900

FF3 = 4083

I can convert the ones there are not negative.

I tried this one

long decimal_answer = strtoul("EC3", NULL, 16);

but it only works on positive numbers.

I am just started with arduino, so i am not that skilled :slight_smile:

In C# i use Convert.ToInt16("EC3", 16) and that works, maybe arduino have some simular ?

but it only works on positive numbers.

That's what happens when you use str(int) to u(nsigned) l(ong).

Can you guess what the function is to convert a str(int) to l(ong) is?

No surprise that you only got positive numbers. strtoul() converts to unsigned long. Try strtol(). You might have to cast your value to a long to get a sign extension.

First of all you are confusing a number representation (positional numeral system) with a computer data type. Hexa, binary, decimal are ways of representing numbers, int, long, char, float are computer data types capable of storing numbers. At computer level the number representation doesn't exists at all. Once the number is properly stored in memory there is no representation. It isn't binary nor hexadecimal, nor octal. You can chose to display that value in whatever representation fits. And you can do the same when you read or express that value to be stored by the computer:

int a = 125; // decimal
int a = 0x7D; // hexa
int a = 0175; // octal

These are exactly the same for the computer. Variable a is going to be initialized with the same value in every case. It's only a matter of how you write the number in the source code.

Reading a text string and converting it to a number is another process which involves number representation also. As you see functions to convert from string to integral types usually allow to specify the number base.

Negative values are a special case. In decimal we use the conventional leading minus sign (-554) but the computer has it's own convention internally. Sign (or negative values) are only stored in signed data types, using the most significant bit to represent negative values. Then you have another confusion there. The hexadecimal number FDDF is 64991. In the other hand if that is the actual value of two bytes for a signed integral data type using two bytes only, then it's -545. But if those were two values of a signed integral data type using four bytes storage, again that would be 64991.

it is signed values, But I do not understand it completely.

i got it to work in excel too

=MOD(HEX2DEC("FDDF")+2^15;2^16)-2^15

Right, and you used string to UNSIGNED LONG (strtoul()) to convert it. What did you expect?

The C Standard General Utilities Library

long strtol (const char *__nptr, char **__endptr, int __base)

unsigned long strtoul (const char *__nptr, char **__endptr, int __base)

long strtol ( const char * __nptr,
char ** __endptr,
int __base
)

The strtol() function converts the string in nptr to a long value. The conversion is done according to the given base, which must be between 2 and 36 inclusive, or be the special value 0.

The string may begin with an arbitrary amount of white space (as determined by isspace()) followed by a single optional '+' or '-' sign. If base is zero or 16, the string may then include a "0x" prefix, and the number will be read in base 16; otherwise, a zero base is taken as 10 (decimal) unless the next character is '0', in which case it is taken as 8 (octal).

The remainder of the string is converted to a long value in the obvious manner, stopping at the first character which is not a valid digit in the given base. (In bases above 10, the letter 'A' in either upper or lower case represents 10, 'B' represents 11, and so forth, with 'Z' representing 35.)

If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr. If there were no digits at all, however, strtol() stores the original value of nptr in endptr. (Thus, if *nptr is not '\0' but **endptr is '\0' on return, the entire string was valid.)

The strtol() function returns the result of the conversion, unless the value would underflow or overflow. If no conversion could be performed, 0 is returned. If an overflow or underflow occurs, errno is set to ERANGE and the function return value is clamped to LONG_MIN or LONG_MAX, respectively.

unsigned long strtoul ( const char * __nptr,
char ** __endptr,
int __base
)

The strtoul() function converts the string in nptr to an unsigned long value. The conversion is done according to the given base, which must be between 2 and 36 inclusive, or be the special value 0.

The string may begin with an arbitrary amount of white space (as determined by isspace()) followed by a single optional '+' or '-' sign. If base is zero or 16, the string may then include a "0x" prefix, and the number will be read in base 16; otherwise, a zero base is taken as 10 (decimal) unless the next character is '0', in which case it is taken as 8 (octal).

The remainder of the string is converted to an unsigned long value in the obvious manner, stopping at the first character which is not a valid digit in the given base. (In bases above 10, the letter 'A' in either upper or lower case represents 10, 'B' represents 11, and so forth, with 'Z' representing 35.)

If endptr is not NULL, strtoul() stores the address of the first invalid character in *endptr. If there were no digits at all, however, strtoul() stores the original value of nptr in endptr. (Thus, if *nptr is not '\0' but **endptr is '\0' on return, the entire string was valid.)

The strtoul() function return either the result of the conversion or, if there was a leading minus sign, the negation of the result of the conversion, unless the original (non-negated) value would overflow; in the latter case, strtoul() returns ULONG_MAX, and errno is set to ERANGE. If no conversion could be performed, 0 is returned.

Thx for pointing me in the right direction.

It solved with this line.

signed int answer = strtol("F4AC", NULL, 16);

But now i got the next question.

I works on my Uno, i get the -2900

But on my Teensy LC i get 62636

Any ideers?

1 Like

The Teensy probably has something other than a 2 byte integer and the sign extension is not happening.

Your best bet is to copy your Excel method into C.

Now i did find a solution for that.

signed int answer = (int16_t)(strtol("F4AC"), NULL, 16));

Now i did find a solution for that.

The name of the function should give you a clue. str(ing) to l(ong) does NOT return an int.

RobertIversen:
Now i did find a solution for that.

signed int answer = (int16_t)(strtol("F4AC"), NULL, 16));

Just in case you missed what Delta_G wrote, here's something you can run.
Sketch:

void setup() 
{
  Serial.begin( 115200 ); // set serial monitor to match

  int answer = 0xF4AC; // 0x tells the compiler that the following chars are supposed to be hexadecimal.

  Serial. print( "\n hex 0xF4AC = decimal " );
  Serial. println( answer );
}

void loop() {}

Results:

hex F4AC = decimal -2900

If you still ain't sure, change the source to a different hex value or feed it binary (starts with 0b and is all 0's and 1's).