Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

size_t divided by int type conversion rules

When I am doing arithmetic operations with size_t type (or unsigned long), how careful should I be with decorating integer constants with type literals. For example,

size_t a = 1111111;
if (a/2 > 0) ...;

What happens when compiler does the division? Does it treat 2 as integer or as unsigned integer? If the former, then what is the resulting type for (unsigned int)/(int)?

Should I always carefully write 'u' literals

if (a/2u > 0) ...;
for (a=amax; a >= 0u; a -= 3u) ...;

or compiler will correctly guess that I want to use operations with unsigned integers?

like image 946
John Smith Avatar asked Jun 02 '15 14:06

John Smith


2 Answers

2 is indeed treated as an int, which is then implicitly converted to size_t. In a mixed operation size_t / int, the unsigned type "wins" and signed type gets converted to unsigned one, assuming the unsigned type is at least as wide as the signed one. The result is unsigned, i.e. size_t in your case. (See Usual arithmetic conversions for details).

It is a better idea to just write it as a / 2. No suffixes, no type casts. Keep the code as type-independent as possible. Type names (and suffixes) belong in declarations, not in statements.

like image 111
AnT Avatar answered Oct 14 '22 13:10

AnT


  • The C standard guarantees that size_t is an unsigned integer.
  • The literal 2 is always of type int.
  • The "usual artihmetic converstions guarantee that whenever an unsigned and a signed integer of the same size ("rank") are used as operands in a binary operation, the signed operand gets converted to unsigned type.

So the compiler actually interprets the expression like this:

a/(size_t)2 > (size_t)0

(The result of the > operator or any relational operator is always of type int though, as a special case for that group of operators.)

Should I always carefully write 'u' literals

Some coding standards, most notably MISRA-C, would have you do this, to make sure that no implicit type promotions exist in the code. Implicit promotions or conversions are very dangerous and they are a flaw in the C language.

For your specific case, there is no real danger with implicit promotions. But there are cases when small integer types are used and you might end up with unintentional change of signedness because of implicit type promotions.

There is never any harm with being explicit, although writing an u suffix to every literal in your code may arguably reduce readability.

Now what you really must do as a C programmer to deal with type promotion dangers, is to learn how the integer promotions and usual arithmetic conversions work (here's some example on the topic). Sadly, there are lots of C programmers who don't, veterans included. The result is subtle, but sometimes critical bugs. Particularly when using the bit-wise operators such as shifts, where change of signedness could invoke undefined behavior.

These rules can be somewhat tricky to learn as they aren't really behaving rationally or consistently. But until you know these rules in detail you have to be explicit with types.


EDIT: To be picky, the size of size_t is actually not specified, all the standard says is that it must be large enough to at least hold the value 65535 (2 bytes). So in theory, size_t could be equal to unsigned short, in which case promotions would turn out quite different. But in practice I doubt that scenario is of any interest, since I don't believe there exists any implementation where size_t is smaller than unsigned int.

like image 24
Lundin Avatar answered Oct 14 '22 13:10

Lundin