I'm investigating a standard for my team around using size_t
vs int
(or long
, etc). The biggest drawback I've seen pointed out is that taking the difference of two size_t objects can cause problems (I'm unsure of specific problems -- maybe something wasn't 2s complemented and the signed/unsigned angers the compiler). I wrote a quick program in C++ using the V120 VS2013 compiler that allowed me to do the following:
#include <iostream> main() { size_t a = 10; size_t b = 100; int result = a - b; }
The program resulted in -90
, which although correct, makes me nervous about type mismatches, signed/unsigned problems, or just plain undefined behavior if the size_t happens to get used in complex math.
My question is if it's safe to do math with size_t objects, specifically, taking the difference? I'm considering using size_t as a standard for things like indexes. I've seen some interesting posts on the topic here, but they don't address the math issue (or I missed it).
What type for subtracting 2 size_t's?
typedef for a signed type that can contain a size_t?
Subtracting two std::size_t s will yield a new std::size_t † and its value will be determined by wrapping. In your example, assuming 64 bit size_t , a - b will equal 18446744073709551526 . This does not fit into an (commonly used 32 bit) int , so an implementation defined value is assigned to result .
When writing C code you should always use size_t whenever dealing with memory ranges. The int type on the other hand is basically defined as the size of the (signed) integer value that the host machine can use to most efficiently perform integer arithmetic.
size_t is commonly used for array indexing and loop counting. Programs that use other types, such as unsigned int, for array indexing may fail on, e.g. 64-bit systems when the index exceeds UINT_MAX or if it relies on 32-bit modular arithmetic.
Since size_t must be an unsigned type, you first need to check explicitly if your float is negative: The behaviour on converting a float that's less than or equal to -1 to an unsigned type is undefined. The second job you need to do is to check that the float is within the upper range of size_t .
This is not guaranteed to work portably, but is not UB either. The code must run without error, but the resulting int
value is implementation defined. So as long as you are working on platforms that guarantee the desired behavior, this is fine (as long as the difference can be represented by an int
of course), otherwise, just use signed types everywhere (see last paragraph).
Subtracting two std::size_t
s will yield a new std::size_t
† and its value will be determined by wrapping. In your example, assuming 64 bit size_t
, a - b
will equal 18446744073709551526
. This does not fit into an (commonly used 32 bit) int
, so an implementation defined value is assigned to result
.
To be honest, I would recommend to not use unsigned integers for anything but bit magic. Several members of the standard committee agree with me: https://channel9.msdn.com/Events/GoingNative/2013/Interactive-Panel-Ask-Us-Anything 9:50, 42:40, 1:02:50
Rule of thumb (paraphrasing Chandler Carruth from the above video): If you could count it yourself, use int
, otherwise use std::int64_t
.
†Unless its conversion rank is less than int
, e.g. if std::size_t
is unsigned short
. In that case, the result is an int
and everything will work fine (unless int
is not wider than short
). However
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With