What is the difference between literals and variables in C (signed with unsigned short ints)?

I saw the following code in Computer Systems' book: "Programmer's Perspective," 2 / E. This works well and creates the desired result. The conclusion can be explained by the difference between signed and unsigned submissions.

#include<stdio.h> int main() { if (-1 < 0u) { printf("-1 < 0u\n"); } else { printf("-1 >= 0u\n"); } return 0; } 

The above code gives -1 >= 0u , however the following code, which should be the same as above, does not work! In other words,

 #include <stdio.h> int main() { unsigned short u = 0u; short x = -1; if (x < u) printf("-1 < 0u\n"); else printf("-1 >= 0u\n"); return 0; } 

gives -1 < 0u . Why did this happen? I can not explain it.

Please note that I had the same questions as, but they do not help.

PS. As @Abhineet said, the dilemma can be solved by changing short to int . However, how to explain these phenomena? In other words, -1 in 4 bytes is 0xff ff ff ff , and in 2 bytes it is 0xff ff . Considering them as 2s-complement, which are interpreted as unsigned , they have corresponding values 4294967295 and 65535 . They are both not less than 0 , and I think that in both cases the output should be -1 >= 0u , i.e. x >= u .

Sample output for it on a small Intel system system:

In short:

 -1 < 0u u = 00 00 x = ff ff 

For int:

 -1 >= 0u u = 00 00 00 00 x = ff ff ff ff 
+8
c bit-manipulation twos-complement unsigned-integer integer-promotion
source share
4 answers

The above code gives -1> = 0u

All integer literals (numeric constants) are of type and therefore also signature. By default, they are of type int , which is signed. When you add the suffix u , you turn the literal into an unsigned int .

For any C expression in which you have one operand that is signed and one that is not specified, the alignment rule (formally: ordinary arithmetic conversions ) implicitly converts the unsigned signed type.

Conversion from signed to unsigned is correct (6.3.1.3):

Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one greater than the maximum value that can be represented in the new type until the value is in the range of the new type.

For example, for 32-bit integers in a standard two-component system, the maximum value of unsigned integers is 2^32 - 1 (4294967295, UINT_MAX within .h). The value is greater than the maximum value of 2^32 . And -1 + 2^32 = 4294967295 , so the literal -1 converted to unsigned int with the value 4294967295 . Which is greater than 0.


If you switch types to short, you get a small integer type. This is the difference between the two examples. Whenever a small integer type is part of an expression, the whole promotion rule implicitly converts it to a larger int (6.3.1.1):

If int can represent all values ​​of the original type (as limited in width for a bit field), the value is converted to int; otherwise, it will be converted to unsigned int. They are called whole promotions. All other types are not changed by an integer number of shares.

If short less than int on this platform (as is the case with 32 and 64-bit systems), then any short or unsigned short will therefore always be converted to int , because they can fit inside one.

So, for the expression if (x < u) you actually get if((int)x < (int)u) , which behaves as expected (-1 is less than 0).

+10
source share

You use promotion rules for integer C.

Operators with types less than int automatically advance their operands to int or unsigned int . See Comments for more detailed explanations. There is one more step for binary (two operands) operators if the types still do not match after that (for example, unsigned int vs. int). I will not try to summarize the rules in more detail than this. See Lundin's answer .

This blog post describes this in more detail, with a similar example for yours: a signed and unsigned char. He cites the specification of C99:

If int can represent all values ​​of the original type, this value is equally converted to int; otherwise, it will be converted to unsigned int. They are called whole stocks. All other types do not change through whole promotions.


You can play with this easier on something like godbolt, with a function that returns one or zero . Just look at the compiler output to see what happens.

 #define mytype short int main() { unsigned mytype u = 0u; mytype x = -1; return (x < u); } 
+3
source share

In addition to what you assume, this is not a property of a specific type width, here are 2 bytes versus 4 bytes, but a question about the rules that should be applied. Whole promotion rules indicate that short and unsigned short converted to int on all platforms where the corresponding range of values ​​fits into int . Since this is the case here, both values ​​are saved and get an int type. -1 perfectly representable in int as it is 0 . Thus, the test results -1 less than 0 .

In the case of testing -1 , compared to 0u normal conversion changes the unsigned type to a generic type to which both are converted. -1 , converted to unsigned , is a UINT_MAX value that is greater than 0u .

This is a good example of why you should never use narrow types to do arithmetic or comparison. Use them only if you have a limited size limit. This is rarely the case for simple variables, but mostly for large arrays, where you can really get from storage in a narrow type.

+2
source share

0u not unsigned short , it unsigned int .

Edit :: Explanation of behavior, How is the comparison performed?

As Jens Gustedt replied,

This is called the "normal arithmetic conversion" standard and is applied when two different integer types occur as operands of the same operator.

In essence, that is

if the types have different widths (more precisely, that the standard translates the conversion rank), then it is converted to a wider type, if both types have the same width, except for really strange architectures, unsigned wins from them. Subscribing to an unsigned conversion of -1 with any type always results in the highest represented value of the unsigned type.

A more explanatory blog written by him can be found here .

0
source share

All Articles