27

Is the integer constant's default type signed or unsigned? such as 0x80000000, how can I to decide to use it as a signed integer constant or unsigned integer constant without any suffix?

If it is a signed integer constant, how to explain following case?

printf("0x80000000>>3 : %x\n", 0x80000000>>3);

output:

0x80000000>>3 : 10000000

The below case can indicate my platform uses arithmetic bitwise shift, not logic bitwise shift:

int n = 0x80000000;

printf("n>>3: %x\n", n>>3);

output:

n>>3: f0000000
Victor S
  • 4,021
  • 15
  • 43
  • 54
  • 1
    Usually, `0x80000000` is `INT_MAX + 1`, so it's unsigned. Hence logical shift in the first example. But when you assign it to an `int`, you invoke undefined behaviour, and typically the result is `INT_MIN`. Left shifting negative integers is implementation-defined, often arithmetic shift is used. The difference is that in the latter, you force it to a signed type. – Daniel Fischer Jul 03 '12 at 12:28
  • @DanielFischer `INT_MAX + 1` is UB but `int n = 0x80000000;` is not UB but implementation-defined and the integer conversion in this case is ruled by 6.3.1.3p3 (in C99) – ouah Jul 03 '12 at 18:54
  • @ouah The `INT_MAX + 1` was meant as a mathematical expression, not C. It's correct, however, that converting that to `int` isn't undefined behaviour, but implementation-defined. My bad. – Daniel Fischer Jul 03 '12 at 18:57

2 Answers2

28

C has different rules for decimal, octal and hexadecimal constants.

For decimal, it is the first type the value can fit in: int, long, long long

For hexadecimal, it is the first type the value can fit in: int, unsigned int, long, unsigned long, long long, unsigned long long

For example on a system with 32-bit int and unsigned int: 0x80000000 is unsigned int.

Note that for decimal constants, C90 had different rules (but rules didn't change for hexadecimal constants).

ouah
  • 142,963
  • 15
  • 272
  • 331
  • 1
    The only correct answer so far. (Nits: you didn't specify the rules for octal [see hex], and from C90, hexadecimal literals changed by the addition of the `long long` types). – Daniel Fischer Jul 03 '12 at 12:14
  • but then can't we expect a warning in `int n = 0x80000000;` Because it is assigning a uint32_t to a int32_t and somehow overflows ? – mbonnin Jul 03 '12 at 12:29
  • Does this mean the statement "An integer constant like 1234 is an int." in [K&R2] is wrong? – Victor S Jul 03 '12 at 12:37
  • 1
    @VictorS: No, it's correct - 1234 is within the guaranteed minimum range of `int` so it will always have type `int`. – caf Jul 03 '12 at 13:12
  • 2
    @mbonnin some compilers *can* display a warning but the standard does not require a warning. There are implicit conversions between any arithmetic types to any arithmetic types. – ouah Jul 03 '12 at 13:20
  • +1 for the only correct answer to a topic that's widely misunderstood. – R.. GitHub STOP HELPING ICE Jul 03 '12 at 13:29
  • If a compiler included a type whose length was intermediate between that of an `int` and a `long` [e.g. when compiling code for 8-bit microcontrollers a 24-bit type could be useful and I've seen at least one compiler support one as "short long"], could it legitimately participate in the hex constant evaluation? – supercat Jan 19 '15 at 23:43
  • @supercat The only provision in the C Standard for extended integer types in the integer constant typing is: *(c11, 6.4.4.1p6) If an integer constant cannot be represented by any type in its list, it may have an extended integer type, if the extended integer type can represent its value [...]*. For other integer constants, a standard integer type (e.g, `int`, `long`) will be selected. – ouah Jan 20 '15 at 09:08
  • I wanted to check by myself and i confirm that `2147483648 << 1 >> 1` and `0x80000000 << 1 >> 1` look the same, but the latter resolves to 0 (on 32bit `int` machine). – calandoa May 24 '16 at 13:43
  • Also, gcc will ultimately use `unsigned long long` for decimals with the warnings: `integer constant is so large that it is unsigned` and `this decimal constant is unsigned only in ISO C90` – calandoa May 24 '16 at 13:45
  • "For example on a system with 32-bit int and unsigned int: 0x80000000 is unsigned int" - 0x80000000 is perfectly capable of representing a 32-bit signed value which is -2147483648? Why is then "unsigned int" chosen? – Cheshar Feb 11 '18 at 07:02
  • Was the decimal constant rule changed in C95? What were the rules for C90? Do you know the exact section of the ANSI C spec this is documented? – da66en Apr 07 '20 at 14:51
9

It is signed if it fits in a signed integer. To make it unsigned, append a u suffix, e.g. 1234u.

You can convert a signed value to unsigned by assigning it to an unsigned variable.

unsigned int i = 1234u; // no conversion needed
unsigned int i = 1234;  // signed value 1234 now converted to unsigned

For 0x80000000, it will be unsigned if ints are 32 bits on your platform, since it doesn't fit into a signed int.


Another thing to watch out for, though, is that the behaviour of right-shift is platform-dependent. On some platforms it's sign-preserving (arithmetic) and on some platforms it's a simple bitwise shift (logical).

Graham Borland
  • 60,055
  • 21
  • 138
  • 179
  • Updated to answer your additional query. – Graham Borland Jul 03 '12 at 12:11
  • `0x80000000` is not signed but unsigned on 32-bit and 64-bit systems. – ouah Jul 03 '12 at 12:11
  • *It is signed if it fits in a signed integer* I think this statement is wrong. – ouah Jul 03 '12 at 12:15
  • 3
    A decimal integer constant is always signed. For hexadecimal constants, it can fit in a `long` but if it fit in an `unsigned int` it will be `unsigned int`. A signed integer is not a synonym of a signed `int`. The type `long` is also a signed integer type. – ouah Jul 03 '12 at 12:20
  • What happens in conversion ?? Of signed to unsigned ? – Suraj Jain Dec 30 '16 at 17:17