0

I create an unsigned int and unsigned char. Then I assign the -10 value, and the char remains unsigned and gives me a value of 246, but the unsigned int takes the -10 value.

#include <stdio.h>
int main ()
{


unsigned char a;
unsigned int b;
a=-10; 
b=-10;
printf("%d\t%d\n", a,b);

}

Compiling and executing I have this:

246     -10

I have no idea why the unsigned int stills signed, and why the char is unsigned.

Reading the book "The C programming language 2nd edition" I can see char can be unsigned by default depending on the machine.

(I'm running NetBSD as a operating system.)

Why the int is signed while I'm declaring as unsigned int, and why the char is taking the value 246?

Is this a compiler or system operating "feature" ?

iBug
  • 35,554
  • 7
  • 89
  • 134
VMS
  • 3
  • 4
  • 6
    Because `%d` is for signed integers. – tkausl Dec 22 '17 at 03:48
  • 1
    `%d` tells the function to “interpret” that argument as a signed integer, regardless of its declaration (as long as it passes the compiler's semantic check) – Andy Pan Dec 22 '17 at 03:51
  • why the char can't get the -10 value then? – VMS Dec 22 '17 at 03:54
  • It can get the -10 value if I create a normal char – VMS Dec 22 '17 at 03:57
  • 2
    It illegal to use `%d` to `printf` an `unsigned int` value that is greater than `INT_MAX`. The behavior is undefined, the output is nonsensical. There's no point in askking "why" questions about undefined behavior. – AnT stands with Russia Dec 22 '17 at 03:59
  • 1
    @AnT - it is not "illegal" to use `%d` format for an `unsigned int`. It gives undefined behaviour. There's a difference. – Peter Dec 22 '17 at 04:04
  • @Peter: It depends on what meaning you assign to "illegal". It is not a strictly defined term. – AnT stands with Russia Dec 22 '17 at 04:06
  • so many duplicates and related questions here https://stackoverflow.com/q/41399092/995714 https://stackoverflow.com/q/47599120/995714 https://stackoverflow.com/q/47739874/995714 https://stackoverflow.com/q/32344810/995714... – phuclv Dec 22 '17 at 04:13
  • @AnT - English dictionary definitions of illegal amount to "forbidden by law, statute, regulation or official rules". The meaning of "undefined" in the C standard (essentially "this standard does not constrain what happens") has nothing in common with this. – Peter Dec 22 '17 at 04:13
  • 1
    @Peter: "English dictionary" has very little to do with this. The language specification explicitly permits compilers to refuse to compile code that contains undefined behavior. This means that in general case this might be as "illegal" as regular syntax errors. Or it might not be... – AnT stands with Russia Dec 22 '17 at 04:15
  • @AnT - the language specification also allows an implementation to NOT diagnose undefined behaviour. That's the point. – Peter Dec 22 '17 at 04:17
  • @Lưu Vĩnh Phúc sorry, I saw no questions like this one when I was looking for. Just questions about casting signed to unsigned and something like this – VMS Dec 22 '17 at 04:20
  • What makes you think assigning a negative value to an unsigned variable makes any sense? – Lundin Dec 22 '17 at 10:59
  • The result made me think that – VMS Dec 23 '17 at 01:20

3 Answers3

1

This is undefined behavior when you pass unsigned integers to %d. Wrong format specifier is UB.

If you assign a negative value to an unsigned variable, it's fine and the value will be taken modulo UINT_MAX + 1 (or UCHAR_MAX + 1), so (-10) % (UCHAR_MAX + 1) = 256 - 10 = 246, and b is 4294967296 - 10 = 4294967286. Unsigned integral overflow is required to wrap-around.

When printf is interpreting these numbers, it finds 246 is suitable for %d, the format specifier for signed int, and 4294967286 is reinterpreted as -10. That's all.

iBug
  • 35,554
  • 7
  • 89
  • 134
  • So the int really is not unsigned, I was thinking it was signed even I was declaring as unsigned. Thanks to all – VMS Dec 22 '17 at 04:12
  • @VMS It *is* unsigned indeed. It is re-interpreted as signed when printing. – iBug Dec 22 '17 at 04:15
  • lol sorry, I wanted to say "the int really is unsigned" – VMS Dec 22 '17 at 04:21
  • "...4294967286 is converted to -10". That's misleading. Standard `printf` is not capable of performing *conversions*, since it has no knowledge of the source type. The best it can do is *reinterpretation*. But formally the behavior is undefined. – AnT stands with Russia Dec 22 '17 at 18:06
  • @AnT Thanks for pointing out. Sorry for my bad English :( – iBug Dec 23 '17 at 01:11
  • Note: passing char to %d is well-defined on most systems because of integer promotions (the exception would be a system where char was both unsigned and the same size as int).. – plugwash Jun 04 '18 at 16:22
1

When you assign -10 to an unsigned char variable, the value is reduced modulo UCHAR_MAX + 1, which results in 246 on your platform. Printing an unsigned char value using format %d is fine on most platforms. The value gets implicitly converted to int, which is the correct type for %d format. So, you see that 246 as you should.

When you assign -10 to an unsigned int variable, the value is reduced modulo UINT_MAX + 1, which results in some large value (depends on the range of unsigned int on your platform). Printing such large unsigned int value (greater than INT_MAX) using format %d leads to undefined behavior. The output is meaningless.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
0

%d is the specifier used to print signed int, so it is not strange. Use %u instead.

http://www.cplusplus.com/reference/cstdio/printf/

And when you assign a negative value to an unsigned variable you will get overflow. That's why you get strange values.

printf("%d", a) means that will take the content of variable a and interpret it as a signed int.

Oh, and btw. You are causing undefined behavior which implies that there's really no reason to ask why something happens. Undefined behavior will always be undefined. Avoid it at all costs. Note that the only thing that is undefined is the printf statement. Assigning a value that's out of range to an unsigned variable is a defined behavior. However, the opposite is not true. int a = UINT_MAX will cause undefined behavior.

klutt
  • 30,332
  • 17
  • 55
  • 95
  • 246 4294967286 That's what I have if I use %u instead – VMS Dec 22 '17 at 03:51
  • are they substracting 10 of their maximum possible value? Why those numbers? – VMS Dec 22 '17 at 03:52
  • @VMS - Because that's what the standard requires. Overflow of unsigned integral types uses modulo arithmetic. So `-10` converted to an `unsigned` gives a result of `UINT_MAX + 1 - 10` where `UINT_MAX` (available in ``) is the maximum value an `unsigned` can represent. A typical 32-bit `unsigned` type has `UINT_MAX` equal to `4294967295`. – Peter Dec 22 '17 at 04:02
  • @klutt That's why I'm asking, Unsigned means like you say The variable cannot handle negative numbers, but the int still handling it while the char cannot – VMS Dec 22 '17 at 04:07
  • @VMS No, the printf statement *interpret* the content in the variable as a signed int. That's a difference. – klutt Dec 22 '17 at 04:12
  • Yes, now I understand, thanks to all guys – VMS Dec 22 '17 at 04:13