sscanf with hexadecimal negative value - c

I need to convert hexadecimal 4-digits values to decimal so I used ssscanf but it is not work on negative numbers...
For example,
int test;
sscanf("0xfff6","%x",&test);
return 65526 instead of -10.
How can I resolve that ?

You have to do it manually. x conversion specifier performs a conversion from an unsigned int and it requires an argument of type pointer to unsigned int. For example with a cast:
unsigned int test;
int result;
sscanf("0xfff6","%x", &test);
result = (int16_t) test;

The fact that the value of test is greater than 32k indicates it's a "long" integer (32 bit)...thus it doesn't see the sign bit. You would have to read the value into an unsigned short integer, then type cast it to a signed short, in order to see the negative value...

I think the core issue is that you are assuming that an int is 16 bits, whereas in your system it appears to be larger than that.
Int is always signed, so the fact that it is reporting the result as 65525 proves that INT_MAX is greater than the 16 bit value of 36727.
Try changing your code from int text to short test and I suspect it will work.

It's probably because your integers are more than 16 bits wide so that fff6 is indeed positive - you may need fffffff6 or even wider to properly represent a negative number.
To fix this, simply place the following after the scanf:
if (val > 32767) val -= 65536;
This adjust values with the top bit set (in 16-bit terms) to be negative.

Related

Output of a short int and a unsigned short?

So I'm trying to interpret the following output:
short int v = -12345;
unsigned short uv = (unsigned short) v;
printf("v = %d, uv = %u\n", v, uv);
Output:
v = -12345
uv = 53191
So the question is: why is this exact output generated when this program is run on a two's complement machine?
What operations lead to this result when casting the value to unsigned short?
My answer assumes 16-bit two's complement arithmetic.
To find the value of -12345, take 12345, complement it, and add 1.
12345 is 0x3039 is 0011000000111001.
Complementing means changing all the 1's to 0's and all the 0's to 1's:
1100111111000110 is 0xcfc6 is 53190.
Add one: 53191.
So internally, -12345 is represented by 0xcfc7 = 53191.
But if you interpret it as an unsigned number, it's obviously just 53191. (And when you assign a signed value to an unsigned integer of the same size, what typically ends up happening is that you assign the exact bit pattern, without converting anything. Later, however, you will typically interpret that value differently, such as when you print it with %u.)
Another, perhaps easier way to think about this is that 16-bit arithmetic "wraps around" at 216 = 65536. So you can think of 65536 as being another name for 0 (just like 0:00 and 24:00 are both names for midnight). So -12345 is 65536 - 12345 = 53191.
The conversion rules, when converting signed integer to an unsigned integer, defined by C standard requires by repeatedly adding the TYPE_MAX + 1 to the value.
From 6.3.1.3 Signed and unsigned integers:
Otherwise, if the new type is unsigned, the value is converted by
repeatedly adding or subtracting one more than the maximum value that
can be represented in the new type until the value is in the range of
the new type.
If USHRT_MAX is 65535 and then adding 65535 + 1 + -12345 is 53191.
The output seen does not depend on 2's complement nor 16 or 32- bit int. The output seen is entirely defined and would be the same on a rare 1's complement or sign-magnitude machine. The result does depend on 16-bit unsigned short
-12345 is within the minimum range of a short, so no issues with that assignment. When a short is passed as a ... argument, is goes thought the usual promotion to an int with no change in value as all short are in the range of int. "%d" expects an int, so the output is "-12345"
short int v = -12345;
printf("%d\n", v); // output "-12345\n"
Assigning a negative number to a unsigned type is well defined. With a 16-bit unsigned short, the value of uv is -12345 plus the minimum multiples of USHRT_MAX+1 (65536 in this case) to a final value of 53191.
Passing an unsigned short as an ... argument, the value is converted to int or unsigned, whichever type contains the entire range of unsigned short. IAC, the values does not change. "%u" matches an unsigned. It also matches an int whose values are expressible as either an int or unsigned.
short int v = -12345;
unsigned short uv = (unsigned short) v;
printf("%u\n", v); // output "53191\n"
What operations lead to this result when casting the value to unsigned short?
The casting did not affect the final outcome. The same result would have occurred without the cast. The cast may be useful to quiet warnings.

signed and unsigned integer in C

I have wrote this program as an exercise to understand how the signed and unsigned integer
work in C.
This code should print simply -9 the addition of -4+-5 stored in variable c
#include <stdio.h>
int main (void) {
unsigned int a=-4;
unsigned int b=-5;
unsigned int c=a+b;
printf("result is %u\n",c);
return 0;
}
When this code run it give me an unexpected result 4294967287.
I also have cast c from unsigned to signed integer printf ("result is %u\n",(int)c);
but also doesn't work.
please someone give explanation why the program doesn't give the exact result?
if this is an exercise in c and signed vs unsigned you should start by thinking - what does this mean?
unsigned int a=-4;
should it even compile? It seems like a contradiction.
Use a debugger to inspect the memory stored at he location of a. Do you think it will be the same in this case?
int a=-4;
Does the compiler do different things when its asked to add unsigned x to unsigned y as opposed to signed x and signed y. Ask the compiler to show you the machine code it generated in each case, read up what the instructions do
Explore investigate verify, you have the opportunity to get really interesting insights into how computers really work
You expect this:
printf("result is %u\n",c);
to print -9. That's impossible. c is of type unsigned int, and %u prints a value of type unsigned int (so good work using the right format string for the argument). An unsigned int object cannot store a negative value.
Going back a few line in your program:
unsigned int a=-4;
4 is of type (signed) int, and has the obvious value. Applying unary - to that value yields an int value of -4.
So far, so good.
Now what happens when you store this negative int value in an unsigned int object?
It's converted.
The language specifies what happens when you convert a signed int value to unsigned int: the value is adjusted to it's within the range of unsigned int. If unsigned int is 32 bits, this is done by adding or subtracting 232 as many times as necessary. In this case, the result is -4 + 232, or 4294967292. (That number makes a bit more sense if you show it in hexadecimal: 0xfffffffc.)
(The generated code isn't really going to repeatedly add or subtract 232; it's going to do whatever it needs to do to get the same result. The cool thing about using two's-complement to represent signed integers is that it doesn't have to do anything. The int value -4 and the unsigned int value 4294967292 have exactly the same bit representation. The rules are defined in terms of values, but they're designed so that they can be easily implemented using bitwise operations.)
Similarly, c will have the value -5 + 232, or 4294967291.
Now you add them together. The mathematical result is 8589934583, but that won't fit in an unsigned int. Using rules similar to those for conversion, the result is reduced to a value that's within the range of unsigned int, yielding 4294967287 (or, in hex, 0xfffffff7).
You also tried a cast:
printf ("result is %u\n",(int)c);
Here you're passing an int argument to printf, but you've told it (by using %u) to expect an unsigned int. You've also tried to convert a value that's too big to fit in an int -- and the unsigned-to-signed conversion rules do not define the result of such a conversion when the value is out of range. So don't do that.
That answer is precisely correct for 32-bit ints.
unsigned int a = -4;
sets a to the bit pattern 0xFFFFFFFC, which, interpreted as unsigned, is 4294967292 (232 - 4). Likewise, b is set to 232 - 5. When you add the two, you get 0x1FFFFFFF7 (8589934583), which is wider than 32 bits, so the extra bits are dropped, leaving 4294967287, which, as it happens, is 232 - 9. So if you had done this calculation on signed ints, you would have gotten exactly the same bit patterns, but printf would have rendered the answer as -9.
Using google, one finds the answer in two seconds..
http://en.wikipedia.org/wiki/Signedness
For example, 0xFFFFFFFF gives −1, but 0xFFFFFFFFU gives 4,294,967,295
for 32-bit code
Therefore, your 4294967287 is expected in this case.
However, what exactly do you mean by "cast from unsigned to signed does not work?"

unexpected behavior of unsigned variables when assigned negative values

Here is a code snippet:
unsigned short a=-1;
unsigned char b=-1;
char c=-1;
unsigned int x=-1;
printf("%d %d %d %d",a,b,c,x);
Hhy the output is this:
65535 255 -1 -1
?
Can anybody please analyze this ?
You are printing the values using %d which is for signed numbers. The value is "converted" to a signed number (it actually stays the same bitwise, but the first bit is interpreted differently).
As for unsigned char and short - they are also converted to 32 bit int, so the values fit in it.
Had you used %lld (and cast the value as long long, otherwise it could be unspecified behavior) even the last two numbers may get printed as unsigned.
Anyway, use %u for unsigned numbers.
How does it work?
Bit value of 255 is 11111111. If treated like an unsigned number, it will be 255. If treated as a signed number - it'll be -1 (the first bit usually determines sign).
When you pass the value to %d in printf, the value is converted to a 32 bit integer, which looks like this: 00000000000000000000000011111111. Since the first bit is 0, the value is printed simply as 255. It works similarily for your short.
The situation is different for 32 bit integer. It is immediately assigned a 11111111111111111111111111111111 value, which stands for -1 in singed notation. And since you have used %d in your printf, it is interpreted as -1.
Basically, you should not assign negative values to "unsigned" variables. You are trying to play tricks on the compiler, and who knows what it will do. Now, "char n = -1;" is OK because "n" can legitimently take on negative values and the compiler knows how to treat it.

Assigning negative numbers to an unsigned int?

In the C programming language, unsigned int is used to store positive values only. However, when I run the following code:
unsigned int x = -12;
printf("%d", x);
The output is still -12. I thought it should have printed out: 12, or am I misunderstanding something?
The -12 to the right of your equals sign is set up as a signed integer (probably 32 bits in size) and will have the hexadecimal value 0xFFFFFFF4. The compiler generates code to move this signed integer into your unsigned integer x which is also a 32 bit entity. The compiler assumes you only have a positive value to the right of the equals sign so it simply moves all 32 bits into x. x now has the value 0xFFFFFFF4 which is 4294967284 if interpreted as a positive number. But the printf format of %d says the 32 bits are to be interpreted as a signed integer so you get -12. If you had used %u it would have printed as 4294967284.
In either case you don't get what you expected since C language "trusts" the writer of code to only ask for "sensible" things. This is common in C. If you wanted to assign a value to x and were not sure whether the value on the right side of the equals was positive you could have written unsigned int x = abs(-12); and forced the compiler to generate code to take the absolute value of a signed integer before moving it to the unsigned integer.
The int is unsinged, but you've told printf to look at it as a signed int.
Try
unsigned int x = -12; printf("%u", x);
It won't print "12", but will print the max value of an unsigned int minus 11.
Exercise to the reader is to find out why :)
Passing %d to printf tells printf to treat the argument as a signed integer, regardless of what you actually pass. Use %u to print as unsigned.
It all has to do with interpretation of the value.
If you assume 16 bit signed and unsigned integers, then here some examples that aren't exactly correct, but demonstrate the concept.
0000 0000 0000 1100 unsigned int, and signed int value 12
1000 0000 0000 1100 signed int value -12, and a large unsigned integer.
For signed integers, the bit on the left is the sign bit.
0 = positive
1 = negative
For unsigned integers, there is no sign bit.
the left hand bit, lets you store a larger number instead.
So the reason you are not seeing what you are expecting is that.
unsigned int x = -12, takes -12 as an integer, and stores it into x. x is unsigned, so
what was a sign bit, is now a piece of the value.
printf lets you tell the compiler how you want a value to be displayed.
%d means display it as if it were a signed int.
%u means display it as if it were an unsigned int.
c lets you do this kind of stuff. You the programmer are in control.
Kind of like a firearm.
It's a tool.
You can use it correctly to deal with certain situations,
or incorrectly to remove one of your toes.
one possibly useful case is the following
unsigned int allBitsOn = -1;
That particular value sets all of the bits to 1
1111 1111 1111 1111
that can be useful sometimes.
printf('%d', x);
Means print a signed integer. You'll have to write this instead:
printf('%u', x);
Also, it'll still not print "12", it's going to be "4294967284".
They do store positive values. But you're outputting the (very high) positive value as a signed integer, so it gets re-interpreted again (in an implementation-defined fashion, I might add).
Use the format flag "%u instead.
Your program has undefined behavior because you passed the wrong type to printf (you told it you were going to pass an int but you passed an unsigned int). Consider yourself lucky that the "easiest" thing for the implementation to do was just silently print the wrong value and not jump to some code that does something harmful...
What you are missing is that the printf("%d",x) expects x to be signed, so although you assign -12 to x it is interpreted as 2's complement which would be a very large number.
However when you pass this really large number to printf it interprets it as signed thus correctly translating it back to -12.
The correct syntax to print a unsigned in print f is "%u" - try this and see what it does!
The assignment of a negative value to an unsigned int does not compute the absolute value of the negative: it interprets as an unsigned int the binary representation of the negative value, i.e., 4294967284 (2^32 - 12).
printf("%d") performs the opposite interpretation. This is why your program displays -12.
int and unsigned int are used to allocate a number of bytes to store a value nothing more.
The compiler should give warnings about signed mismatching but it really does not affect the bits in the memory that represent the value -12.
%x, %d, %u etc tells the compiler how to interrupt a number of bits when you print them.
When you are trying to display the int value you are passing it to a (int) argument and not a (unsigned int) argument and that causes it to print -12 and not 4294967284. Integers are stored in hexadecimal format and -12 for int is the same as 4294967284 for unsigned int in hexadecimal format..
That is why "%u" prints the right value you want and not "%d".. It depends on your argument type..GOOD LUCK!
The -12 is in 16-bit 2's compliment format. So do this:
if (x & 0x8000) { x = ~x+1; }
This will convert the 2's compliment -ve number to the equivalent +ve number. Good luck.
When the compiler implicitly converts -12 to an unsigned integer, the underlying binary representation remains unaltered. This conversion is purely semantic. The sign bit of the two's complement integer becomes the most significant bit of the unsigned integer. Thus when printf treats the unsigned integer as a signed integer with %d, it will see -12.
In general context when only positive numbers can be stored, negative numbers are not stored explicitly but their 2's complement is stored. In the same way here, the 2's complement of -12 will be stored in 'x' and you use %u to get it.

Integer overflow problem

Please explain the following paragraph.
"The next question is whether we can assign a certain value to a variable without losing precision. It is not sufficient if we just check for overflow during the addition or subtraction, because someone might add 1 to -5 and assign the result to an unsigned int. Then the actual addition does not overflow, but the result still does not fit."
when i am adding 1 to -5 i dont see any reason to worry.the answer is as it should be -4.
so what is the problem of result not being fit??
you can find the full article here through which i was going:
http://www.fefe.de/intof.html
The binary representation of -4, in a 32-bit word, is as follows (hex notation)
0xfffffffc
When interpreted as an unsigned integer, this bit pattern represents the number 2**32-4, or 18446744073709551612. I'm not sure I would call this phenomenon "overflow", but it is a common mistake to assign a small negative integer to a variable of unsigned type and wind up with a really big positive integer.
This trick is actually exploited for bounds checking: if you have a signed integer i and want to know if it is in the range 0 <= i < n, you can test
if ((unsigned)i < n) { ... }
which gives you the answer using one comparison instead of two. The cast to unsigned has no run-time cost; it just tells the compiler to generate an unsigned comparison instead of a signed comparison.
Try assigning it to a unsigned int, not an int.
The term unsigned int is the key - by default an int datatype will hold negative and positive numbers; however, unsigned ints are always positive. They provide this option because uints can technically hold greater positive values than regular signed ints because they do not need to use a bit to keep track of whether or not its negative or positive.
Please see:
Signed versus Unsigned Integers
The problem is that you're storing -4 in an unsigned int. Unsigned ints can only contain zero and positive values. If you assign -4 to one, you'll actually end up getting a very large positive number (the actual value depends on how wide an int you're using).
The problem is that the sizes of storage such as unsigned int can only hold so much. With 1 and -5 it does not matter, but with 1 and -500000000 you might end up with a confusing result. Also, unsigned storage will interpret anything stored in it as positive, so you cannot put a negative value in an unsigned variable.
Two big things to watch out for:
1. Overflow in the operation itself: 1 + -500000000
2. Issues in casting: (unsigned int)(1 + -500)
Unsigned variables, like unsigned int, cannot hold negative values. So assigning 1 - 5 to an unsigned int won't give you -4. I'm not sure what it'll give you, it's probably compiler specific.
Some code:
signed int first, second;
unsigned int result;
first = obtain(); // happens to be 1
second = obtain(); // happens to be -5
result = first + second; // unexpected result here - very large number - and it's too late to check that there's a problem
Say you obtained those values from keyboard. You need to check before addition that the result can be represented in unsigned int. That's what the article talks about.
By definition the number -4 cannot be represented in an unsigned int. -4 is a signed integer. The same goes for any negative number.
When you assign a negative integer to an unsigned int the actual bits of the number do not change, but they are merely represented differently. You'll get some ridiculously-large number due to the way integers are represented in binary (two's complement).
In two's complement, -4 is represented as 0xfffffffc. When 0xfffffffc is represented as an unsigned int you'll get the number 4,294,967,292.
You have to remember that fundamentally you're working with bits. So you can assign a value of -4 to an unsigned integer and this will place a series of bits into that memory location. Those bits can be interpreted as -4 in certain circumstances. One such circumstance is the obvious one: you've told the compiler/system that the bits in that memory location should be interpreted as a two's compliment signed number. So if you do printf("%s",i) prtinf does its magic and converts the two's compliment number to a magnitude and sign. The magnitude will be 4 and the sign will be negative, so it displays '-4'.
However, if you tell the compiler that the data at that memory location is not signed then the bits don't change but instead their interpretation does. So when you do your addition, store the result in an unsigned integer memory location and then call printf on the result it doesn't bother looking for the sign because by definition it is always positive. It calculates the magnitude and prints it. The magnitude will be off because the sign information is still encoded in the bits but it's treated as magnitude information.

Resources