-250 prints as 6 - c

I could not identify how the following program outputs 6 and -250.
#include<stdio.h>
int main()
{
unsigned char p=-250;
printf("%d",p);
unsigned int p1=-250;
printf("%d",p1);
return 0;
}
Being an unsigned integer it has to output only the positive values.How does the p value outputs 6? Please help me understand.

printf is not typesafe. It prints whatever you ask it to, and %d says "signed integer". It is your responsibility to provide a varibale of matching type. Since the unsigned char is only 8 bits wide, the literal -250 wraps around to +6, which remains +6 when interpreted as a signed integer. Note that char and short int (and their signed/unsigned counterparts) all get promoted to int-types when passed via variadic arguments.

By default, integer numerals such as -250 have a type int. Also, negative values stores in memory in Two's complement form. Let calculate two's complement form of -250 (see Making two's complement form paragraph in wiki):
Positive 250 is a 11111010 (first 8 bits, leading zeros are omitted)
Complement it and get 00000101 (first 8 bits, leading ones are omitted)
Add one and get 00000110 (first 8 bits, leading ones are omitted)
Type conversion rules for integer types in C says that we should drop left bits to get 8-bit char. For more details look K&R A.6.2 (well, it is for russian edition, maybe in original book it has another place).
So unsigned char p gets exactly a 00000110 value (6 in decimal). That is why you get 6 in output.
I think, you understand now why there is -250 in second printf ;)

unsigned char may consist only of numbers 0..255
numbers are converted modulo 256. So -250 casted to 6
You should not trust this behaviour. you should avoid overflow.
As of p1, it casted to unsigned int, but interpried as p1 in printf() because of %d identifier

p1 is unsigned, but the %d modifier treats the corresponding argument as signed, so even though in fact it is positive, it is printed as negative.
Whether a number is signed or unsigned is all about the representation that is applied, at the machine level it doesn't make a difference.

Related

How does hexadecimal to %x work?

I am learning in C and I got a question regarding this conversion.
short int x = -0x52ea;
printf ( "%x", x );
output:
ffffad16
I would like to know how this conversion works because it's supposed to be on a test and we won't be able to use any compilers. Thank you
I would like to know how this conversion works
It is undefined behavior (UB)
short int x = -0x52ea;
0x52ea is a hexadecimal constant. It has the value of 52EA16, or 21,22610. It has type int as it fits in an int, even if int was 16 bit. OP's int is evidently 32-bit.
- negates the value to -21,226.
The value is assigned to a short int which can encode -21,226, so no special issues with assigning this int to a short int.
printf("%x", x );
short int x is passed to a ... function, so goes through the default argument
promotions and becomes an int. So an int with the value -21,226 is passed.
"%x" used with printf(), expects an unsigned argument. Since the type passed is not an unsigned (and not an int with a non-negative value - See exception C11dr ยง6.5.2.2 6), the result is undefined behavior (UB). Apparently the UB on your machine was to print the hex pattern of a 32-bit 2's complement of -21,226 or FFFFAD16.
If the exam result is anything but UB, just smile and nod and realize the curriculum needs updating.
The point here is that when a number is negative, it's structured in a completely different way.
1 in 16-bit hexadecimal is 0001, -1 is ffff. The most relevant bit (8000) indicates that it's a negative number (admitting it's a signed integer), and that's why it can only go as positive as 32767 (7fff), and as negative as -32768 (8000).
Basically to transform from positive to negative, you invert all bits and sum 1. 0001 inverted is fffe, +1 = ffff.
This is a convention called Two's complement and it's used because it's quite trivial to do arithmetic using bitwise operations when you use it.

Difference between '(unsigned)1' and '(unsigned)~0'

What is the difference between (unsigned)~0 and (unsigned)1. Why is unsigned of ~0 is -1 and unsigned of 1 is 1? Does it have something to do with the way unsigned numbers are stored in the memory. Why does an unsigned number give a signed result. It didn't give any overflow error either. I am using GCC compiler:
#include<sdio.h>
main()
{
unsigned int x=(unsigned)~0;
unsigned int y=(unsigned)1;
printf("%d\n",x); //prints -1
printf("%d\n",y); //prints 1
}
Because %d is a signed int specifier. Use %u.
which prints 4294967295 on my machine.
As others mentioned, if you interpret the highest unsigned value as signed, you get -1, see the wikipedia entry for two's complement.
Your system uses two's complement representation of negative numbers. In this representation a binary number composed of all ones represent the biggest negative number -1.
Since inverting all bits of a zero gives you a number composed of all ones, you get -1 when you re-interpret the number as a signed number by printing it with a %d which expects a signed number, not an unsigned one.
First, in your use of printf you are telling it to print the number as signed ("%d") instead of unsigned ("%u").
Second, you are right in that it has "something to do with the way numbers are stored in memory". An int (signed or unsigned) is not a single bit on your computer, but a collection of k bits. The exact value of k depends on the specifics of your computer architecture, but most likely you have k=32.
For the sake of succinctness, lets assume your ints are 8 bits long, so k=8 (this is most certainly not the case, unless you are working on a very limited embedded system,). In that case (int)0 is actually 00000000, and (int)~0 (which negates all the bits) is 11111111.
Finally, in two's complement (which is the most common binary representation of signed numbers), 11111111 is actually -1. See http://en.wikipedia.org/wiki/Two's_complement for a description of two's complement.
If you changed your print to use "%u", then it will print a positive integer that represents (2^k-1) where k is the number of bits in an integer (so probably it will print 4294967295).
printf() only knows what type of variable you passed it by what format specifiers you used in your format string. So what's happening here is that you're printing x and y as signed integers, because you used %d in your format string. Try %u instead, and you'll get a result more in line with what you're probably expecting.

Bitwise operation on char gives 32 bit result

I've been writing a program in C to move the first 4 bits of a char to the end and the last 4 to the start. For most values it works normally, as well as the reverse operation, but for some values, as 8, x, y, z, it gives as result a 32 bit value. Values checked through printing hex value of the variable. Can anybody explain why this is happening?
#include <stdio.h>
#include <stdlib.h>
int main()
{
char o, f,a=15;
scanf("%c",&o);
printf("o= %d\n",o);
f=o&a;
o=o>>4;
printf("o= %d",o);
o=o|(f<<4);
printf("o= %x, size=%d\n",o,sizeof(o));
f=o&a;
o=o>>4;
printf("o= %d",o);
o=o|(f<<4);
printf("o= %x, size=%d\n",o,sizeof(o));
return 0;
}
Passing o as an argument to printf() results in an automatic conversion to int, which is apparently 32-bit on your system. The automatic conversion uses sign-extension, so if bit 7 in o is set, bits 8-31 in the converted result will be set, which will explain what you are seeing.
You could use unsigned char instead of char to avoid this. Or pass o & 0xff to printf().
Try declaring your variables as unsigned char. You are getting a sign-extension of the upper bit.
A char given as argument to printf (or any variadic function, or any function without prototype) is promoted to int. If char is signed on your platform and the passed value is negative, the sign is extended.
Your values are printed as 32-bit values because your format specifiers %x tell printf to print the value as an unsigned int. To print it as an unsigned char, you need the format specifier %hhx with the hh length modifier. If the values are positive, that makes no difference for the printed output, but for negative numbers it does because they have the most significant bit set.
For the following, explaining how negative values arise in that code, I assume CHAR_BIT == 8 and twos complement representation for negative integers.
For the shifts, the value of o is promoted to int. If the fourth least significant bit of the original value was set (if (o & 8) != 0), after the first swap of the nibbles, the most significant bit of o is set. If char is by default signed on your platform, that means the result is negative. For the second nibble-swap, the value of o is again promoted to int, resulting in a negative value. The right-shifting of negative values is implementation-defined, so
o=o>>4;
is not portable in that case (although, in practice all implementations use either an arithmetic right shift [with sign-extension] or a logical right shift [shifting in zeros from the left]).
On implementations doing an arithmetic shift on negative integers, the four most significant bits of o will all be set, so
o=o|(f<<4);
doesn't change the value anymore.
The only way to portably fix the code to obtain the desired behaviour is to declare o as an unsigned char as suggested by Ned. Then all values are positive and the behaviour of the shifts is well-defined and matches your expectations.

How to explain this,what happens when we cast signed char to int/hex?

signed char num = 220; //DC in hex
printf("%02X\n", num);
printf("%d\n", num);
I know that signed char can only represent -128~127,but why the above outputs:
FFFFFFDC
-36
What's the reason?
UPDATE
My above code is just contrived for my question,that is ,what happens when we cast signed char to int/hex
As our starting point, 220 = DC in hex, and 11011100 in binary.
The first bit is the sign-bit, leaving us with 1011100. Per two's complement, if we complement it (getting 0100011), and then add one, we get 0100100 -- this is 36.
When it converts the signed char to signed int, it doesn't say "this would be 220 if it's unsigned", it says "this is -36, make it an int of -36", for which the 32-bit two's complement representation is FFFFFFDC, because it must be the negative value for the full size of int (this is called sign-extension):
+36 as a 32-bit value: 00000000000000000000000000100100
complement: 11111111111111111111111111011011
add one: 11111111111111111111111111011100
Or, in hex, FFFFFFDC.
This is why you must be careful with printf("%x", ch); (and relatives) -- if you intend to just get a two-digit value, and chars are signed, you may wind up with eight digits instead. Always specify "unsigned char" if you need it to be unsigned.
As you pointed out, the signed car can have a max value of 127. The reason for the negative number there, however, is due to how the char is stored in memory. All signed integer types save the final bit for sign, with 0/1 denoting positive/negative. The compiler, however, does not check overflow, so when you tried to assign num to 220, it overflowed the value into the sign bit since it could not fit it into the first 7 bits of the char (chars are 1 byte). As a result, when you try to read what is in memory, it sees the sign bit as thrown making the compiler think that instead of seeing a large positive number as you intended, it is instead seeing a small negative value. Hence, the output you see.
Edit
Responding to your updated question. All that happens is that the compiler will copy or expand the char to have 4 bytes of memory, interpret the value of the char, and rewrite it in the new int's memory. In you're case, the program at run time would think that the char has a value of -36 instead of 220 because it's interpreting those bits as a signed char before the cast. Then, when it casts, it simply creates an int with value -36.
Your overflow on the assignment, combined with sign extension when you promote it to an int to view it in hex ... see What's happening in the background of a unsigned char to integer type cast?
Any type smaller that "int" gets converted to "int" when it's passed via "...". This means your negative char got converted to negative int, with FFFs showing up in hex printout.

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.

Resources