When comparing a unsigned value, as in this test:
if (pos == (size_t)-1)
Is this comparison technically different from something like:
if (pos == (size_t)~0)
I am not used to the second variant. That's why I am asking the question. The answer may be rather straighforward if it's yes.
The C++ standard guarantees that size_t
is an unsigned type, that unsigned types obey the usual modular arithmetic rules (where the modulus is two to the number of bits in the value representation of the type, cf. 3.9/4), and thus -1
converted to size_t
must be the largest value which that type can represent.
The value 0
is an int
, and ~0
has all the bits in the int
representation of zero flipped. The value of that result depends on the representation of int
on your platform. That value (which may be a trap representation, thanks @Matt McNabb) is then converted to size_t
(which is done following the rules of modular arithmetic).
In conclusion, whether the resulting values compare equal is implementation defined. (For example, if int
is represented in two's complement, then the value of ~0
is -1
, so the two are the same.)
Assuming (guaranteed by the standard) that size_t refers to an unsigned integer value, this:
if(pos == (size_t)~0)
used with the intent to be equivalent to:
if(pos == (size_t)-1)
is assuming that the machine uses a 2's complement representation for negative integers. The standard doesn't enforce it so you shouldn't assume it if you want your code to be 100% portable.
So, in your example technically there is no difference whatsoever. Because it is hard to find a compiler that will not optimize operations on literals like -1
and ~0
. With your example I've got exactly:
; ...
movq $-1, -16(%rbp)
movq $-1, -8(%rbp)
; ...
Don't be afraid of those
-1
's, assebmly is typeless ;)
More interesting question is if your example would be:
#include <stddef.h>
int main() {
int var0 = 0;
int var1 = 1;
size_t a = (size_t) -var1;
size_t b = (size_t) ~var0;
return a ^ b;
}
In my case (Kubuntu, gcc 4.8.2, x86_64, -O0
option) the part of interest was:
movl $0, -24(%rbp) ; var0 = 0
movl $1, -20(%rbp) ; var1 = 1
movl -20(%rbp), %eax
negl %eax ; 2's complement negation
; ...
movl -24(%rbp), %eax
notl %eax ; 1's complement negation
; ...
Looking into Intel's manual:
NEG
- Two's Complement NegationReplaces the value of operand (the destination operand) with its two's complement. (This operation is equivalent to subtracting the operand from 0.)
NOT
- One's Complement NegationPerforms a bitwise NOT operation (each 1 is set to 0, and each 0 is set to 1) on the destination operand and stores the result in the destination operand location.
My conclusion would be, theoretically, code could differ on some exotic platform and compiler, but otherwise – no. And always if unsure check assembly listing on your platform.
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