"Never use a signed type for a number that can never be negative"
One of my pet peeves is developers using int (instead of unsigned ints) for primary keys in database tables.
"Never use a signed type for a number that can never be negative"
One of my pet peeves is developers using int (instead of unsigned ints) for primary keys in database tables.
In this case, it makes absolutely no difference at all. It could be argued that writing unsigned int would make the code slightly harder to read. That said, I like to use stdint.h and unint32_t would, I think, not have any drawbacks.
> there is lot of code out there with interfaces expecting signed ints even though they should using uint
That's not a good reason to not use unsigned integers, it's a zero-overhead cast from unsigned to signed (at the risk of overflowing into the negative).
Using uint limits the optimizer...
Every time I see someone mention the optimization argument for signed integers I ask for examples and I've yet see a good one.
for (int i = x.size() - 1; i >= 0; i--) ...
for (int i = 0; i < x.size() - 1; i++) if (x[i] < x[i+1]) ...
Both will blow up badly with unsigned ints.(Well, to be fair, both will blow up with signed ints if x.size() is greater than 2G, so it's a matter of expectations.)
for( size_t i = x.size(); i-- > 0; ) ...Remember that a for loop does something like this behind the scenes:
size_t i = x.size();
while( i-- > 0 )
{
// your code which needs backwards iteration here
; // do nothing because there is no third statement
}Still, the trick makes it look suspect and that's an argument against using it.
This is true. The code is confusing to people not used to it. A workaround could be to hide this code inside a macro, so people not interested in digging into the code would take the macro's word:
#define REVERSE_LOOP( x, i ) for( size_t i = x.size(); i-- > 0; )
But unfortunately, that doesn't help with the fear that people has against unsigned types.That yields compiler warnings for signed vs unsigned then, no?
// count up
std::size_t i = 0;
while (i != 10)
{
std::cout << i << "\n";
++i;
}
// count down
std::size_t i = 10;
while (i != 0)
{
--i;
std::cout << i << "\n";
}
After initialization a for statement repeats "test; body; advance", this is ideal for counting up loops, but what we need for counting down loops is "test; advance; body". Since C/C++ do not provide the latter as a primitive you have to use a while loop as shown above. Using a signed integer to shoehorn a counting down loop into a for statement at the cost of 1/2 your range is a hack IMO. Note that when working with iterators you have to resort to a while statement as iterating past begin is UB.I'm pretty sure that it's just because "int" is one word and "unsigned int" is two, plus more than twice the characters. I suspect if "int" defaulted to "unsigned int" and you'd have to specify signed ints explicitly, the taboo would be reversed.
Never underestimate the power of trivial inconveniences.
There's example code on the CERT secure coding guidelines here (look under 'Substraction'):
https://www.securecoding.cert.org/confluence/display/seccode...
Writing safe code to calculate the absolute difference between two unsigned integers is much less hairy: max(x,y) - min(y,x).
Really, working directly in fixed-precision arithmetic is absurd. In order to be able to rely on its correctness with any degree of certainty, you need to very carefully track each operation and its bounds, at which point you may as well have just used arbitrary-precision types, explicitly encoded your constraints, and had the compiler optimize things down to scalar types when possible, warning when not.
Fixed-precision arithmetic has one main advantage over arbitrary-precision arithmetic: it is more time- and space-efficient. This advantage only applies if the fixed-precision arithmetic is actually correct and the fixed-precision arithmetic meets some concrete time or space constraint which arbitrary-precision arithmetic fails to meet. It generally takes time and effort to demonstrate that these conditions hold; because one can rely on the correctness of arbitrary-precision arithmetic without doing so, arbitrary-precision arithmetic should then generally be the default choice.
This assumes that you care about making relatively strong guarantees about the correctness of your programs. If for some reason you don't, then sure, use ints and whatnot for everything. If you do, though, I suspect you'll find that it's easier to track down a performance bottleneck caused by using bignums than an obscure bug triggered by GCC applying an inappropriate optimization based on overflow analysis.
1) If you don't need negative numbers, use unsigned integers.
2) If you don't need the extra positive range of unsigned integers (or defined wrapping), use signed.
You advocate (1), but C is generally based on (2), with the default int being signed, and many standard functions using plain int.
Having a negative pkey space is actually useful. In LSMB we reserve all negative id's for test cases, which are guaranteed to roll back. This has a number of advantages including the ability to run a full test run on a production system without any possibility of leaving traces in the db.
[0] though several do support UUIDs, which are essentially unsigned 128-bit ints, and which (with a well-selected generation mechanism) are better as server-assigned surrogate keys than sequential integers, signed or unsigned, anyway.
if (index < 0) { /* error */ }
I die a little inside."SQL only specifies the integer types integer (or int), smallint, and bigint." http://www.postgresql.org/docs/9.3/static/datatype-numeric.h...
Seems like a pretty ignorant pet peeve considering that's the only option for every database that doesn't auto-corrupt data.