0

i do know the differences of signed unsigened etc. But i don´t understand the following code:

unsigned int x = 1;
int y = -1;
    if(y < x)
        printf("of course it is");
    else
        printf("strange stuff");

1 should be a greater number than -1, no matter which representation is used. Because "strange stuff" will be displayed on the console.

jhamra
  • 39
  • 4
  • 3
    The operator (<) cannot compare signed to unsigned, so it converts one of them to the other type. In this case, it converts y to unsigned (which makes it a large number). – L. Scott Johnson Jun 07 '17 at 15:45
  • 1
    **ISO/IEC 9899:2011 (C)** [§6.5.8 Relational operators](http://c0x.coding-guidelines.com/6.5.8.html) -1202 If both of the operands have arithmetic type, the usual arithmetic conversions are performed. Both operands will be casted to be `unsigned int`, and in Two's Complement, `unsigned int y = -1; // = 4294967296 = 2^32 since integers are 32-bit.` Thus you're comparing `4294967296 < 1` which is false. – Miket25 Jun 07 '17 at 16:01
  • Well that explains the outcome. But why will be y converted to an unsigned int. To match the types, x could be converted to Two´s Complement. – jhamra Jun 07 '17 at 18:03

2 Answers2

2

signed 1 (as byte) in bits: 00000001

unsigned 1 in bits: 00000001

signed -1 in bits: 10000001 (or 1 1111111, just details)

unsigned -1 in bits: no valid representation (10000001 is 129)

if you want safely compare signed and unsigned variables, than you have two ways:

1) take in account signs and manually compare them (e. g. isSignedLess = (signed < 0) || ((unsigned <= max_signed) && (signed < unsigned)) )

2) cast both to bigger singed (i. e. signed long long) and than compare them (signed long long can store all diapason of signed/unsigned int's)


As you can see in comments, both ways are kinda tricky. Just don't mix signed and unsigned wherever you can. It's possible in 99% cases. In last 1% cases you really need to know what you doing (e. g. often had to use signed indexes with vectors, but size() - unsigned, so I ask myself hundred time "can this vector reach MAX_INT or not? have I to do more complex code or it's ok for this task?").

Green_Wizard
  • 795
  • 5
  • 11
  • `isSignedLess = (signed < 0) || ((unsigned <= max_signed) && (signed < unsigned))` is the right idea, yet can be simplified. `isSignedLess = (signed_a < 0) || (signed_a < unsigned_b);`. The cast to bigger `signed is not always possible as a wider signed type may not exist. – chux - Reinstate Monica Jun 07 '17 at 17:05
  • First of all, as already was said, it's not recommended mixing signed and unsigned. I'm just wrote a bit hacky workaround. Secondary, `signed_a < unsigned_b` can cause same problem, if compiler decide to trunc unsigned to signed (yeah, "standard saying...."... I don't like to remember tiny details, if there is straightforward and obviously code) – Green_Wizard Jun 07 '17 at 17:49
  • "if compiler decide to trunc unsigned to signed" does not happen in C. – chux - Reinstate Monica Jun 07 '17 at 17:55
  • The is UV-ed because it does not caution against "mixing signed and unsigned". Instead it address OP's issue of how to handle mixed sign-ness compares with #1. – chux - Reinstate Monica Jun 07 '17 at 17:58
  • 1
    On 2nd look `isSignedLess = (signed < 0) || ((unsigned <= max_signed) && (signed < unsigned)))` is wrong. `(unsigned <= max_signed)` incorrectly causes false compare with `unsigned int x = UINT_MAX; int y = 0;` to fail. – chux - Reinstate Monica Jun 07 '17 at 18:02
  • Yes, there is a mistake. – Green_Wizard Jun 07 '17 at 18:18
  • It is possible (however unlikely) for `long` and `long long` types to be the same size, making "`signed long long` can store all diapason of `signed`/`unsigned` `int`s" not strictly true. – ad absurdum Jun 08 '17 at 19:38
1

You're comparing an unsigned int with a signed int. You shouldn't do that. C fixes this by converting one of them to the type of the other. In this case it probably converts y to an unsigned int making it positive so x should be the same as y.

You sould make them both an int, or if it's really necessary you can cast the unsigned int to an int when comparing.

if(y<(int)x)

hellvetica
  • 119
  • 7