[Libreoffice] signed/unsigned comparison (was: [PATCH] Replace SvULongs with vector and code clean up part 1)

Stephan Bergmann stephan.bergmann.secondary at googlemail.com
Tue Aug 9 00:05:49 PDT 2011


On Aug 6, 2011, at 3:32 PM, Maciej Rumianowski wrote:
> I was working on SvULongs in libs-core and I decided to split my work in
> several Patches.
> 
> With this patch comes some questions:
>> @@ -228,9 +229,9 @@ private:
>>     String aValStr;
>>     double nValNum;
>>     sal_Bool bUndoAddList;
>> -    SvULongs aAddList;
>> -    SvULongs aDelList;
>> -    SvULongs aCurEntryList;
>> +    std::vector<sal_uInt32> aAddList;
>> +    std::vector<sal_uInt32> aDelList;
>> +    std::vector<sal_uInt32> aCurEntryList;
[…]
>> @@ -1325,7 +1288,7 @@ String SvxNumberFormatShell::GetComment4Entry(short nEntry)
>>     if(nEntry < 0)
>>         return String();
>> 
>> -    if(nEntry<aCurEntryList.Count())
>> +    if(nEntry < (short)aCurEntryList.size())
>>     {
> 
> 5. Should short type be replaced with sal_Int16 or more appropriate type?

Some C++ compilers warn about comparisons like (x < y) where x is an rvalue of a signed integral type and y is an rvalue of an unsigned integral type.  And, in general, they are right in doing so:  Assume that x is an rvalue -1 of type int and y is some rvalue of type unsigned int.  Usual arithmetic conversion causes the int -1 to be converted to unsigned int. Undefined behavior, hard-disk erased.  Oops.

However, if the programmer can prove that x is always non-negative in the above comparison, there is usually an easy solution to that problem:

First, assert the programmer's knowledge that x is indeed non-negative.  In the original code, that would be

  OSL_ASSERT(nEntry >= 0);

(Which might or might not be considered overkill in this specific case, given the if(nEntry < 0) branch just above the code in question.)

Next, cast x (of signed integral type T) to an unsigned integral type that is known to be able to represent all the non-negative values of T.  (In general, with current C++ implementations, that can be tricky if all you know about T is that it is some typedef.)  But in the original code T is known to be short (and whether that is a good choice is an entirely different question), so that code could be changed to

  if (sal::static_int_cast< unsigned short >(nEntry) < aCurEntryList.size())

Note the use of sal::static_int_cast instead of static_cast---the former was introduced to make it simpler to find all places that need to be adapted should the type of nEntry ever be changed---and is declared and documented in sal/types.h.  (And never use a C-style cast in C++ code.)  Note also that it would also work to cast to a larger type than unsigned short, like unsigned int or unsigned long int.

-Stephan


More information about the LibreOffice mailing list