Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Style question: Use always signed integers or not?

Reply
Thread Tools

Style question: Use always signed integers or not?

 
 
Juha Nieminen
Guest
Posts: n/a
 
      06-07-2008
I was once taught that if some integral value can never have negative
values, it's a good style to use an 'unsigned' type for that: It's
informative, self-documenting, and you are not wasting half of the value
range for values which you will never be using.

I agreed with this, and started to always use 'unsigned' whenever
negative values wouldn't make any sense. I did this for years.

However, I slowly changed my mind: Doing this often causes more
problems than it's worth. A good example:

If you have an image class, its width and height properties can
*never* get negative values. They will always be positive. So it makes
sense to use 'unsigned' for the width and height, doesn't it? What
problems could that ever create?

Well, assume that you are drawing images on screen, by pixel
coordinates, and these images can be partially (or completely) outside
the screen. For example, the left edge coordinate of the image to be
drawn might have a negative x value (for example drawing a 100x100 image
at coordinates <-20, 50>). Since the coordinates are signed and the
dimensions of the image are unsigned, this may cause signed-unsigned
mixup. For example this:

if(x - width/2 < 1) ...

where 'x' is a signed integer, gives *different* results depending on
whether 'width' is signed or unsigned, with certain values of those
variables (for example x=2 and width=10). The intention is to treat
'width' here as a signed value, but if it isn't, the comparison will
malfunction (without explicitly casting 'width' to a signed value). This
may well go completely unnoticed because compilers might not even give
any warning (for example gcc doesn't).

Thus at some point I started to *always* use signed integers unless
there was a very good reason not to. (Of course this sometimes causes
small annoyances because STL containers return an unsigned value for
their size() functions, but that's usually not a big problem.)

It would be interesting to hear other opinions on this subject.
 
Reply With Quote
 
 
 
 
Erik Wikström
Guest
Posts: n/a
 
      06-07-2008
On 2008-06-07 12:43, Juha Nieminen wrote:
> I was once taught that if some integral value can never have negative
> values, it's a good style to use an 'unsigned' type for that: It's
> informative, self-documenting, and you are not wasting half of the value
> range for values which you will never be using.
>
> I agreed with this, and started to always use 'unsigned' whenever
> negative values wouldn't make any sense. I did this for years.
>
> However, I slowly changed my mind: Doing this often causes more
> problems than it's worth. A good example:
>
> If you have an image class, its width and height properties can
> *never* get negative values. They will always be positive. So it makes
> sense to use 'unsigned' for the width and height, doesn't it? What
> problems could that ever create?
>
> Well, assume that you are drawing images on screen, by pixel
> coordinates, and these images can be partially (or completely) outside
> the screen. For example, the left edge coordinate of the image to be
> drawn might have a negative x value (for example drawing a 100x100 image
> at coordinates <-20, 50>). Since the coordinates are signed and the
> dimensions of the image are unsigned, this may cause signed-unsigned
> mixup. For example this:
>
> if(x - width/2 < 1) ...
>
> where 'x' is a signed integer, gives *different* results depending on
> whether 'width' is signed or unsigned, with certain values of those
> variables (for example x=2 and width=10).


Wow, that was certainly an eye-opener. I had assumed that in this case
both values would be promoted to some larger type (signed long) which
could accurately represent both values (the signed and the unsigned int)
but apparently not.

This is a defect in the standard in my opinion since it allows the
correct action to be taken for types smaller than int:

#include <iostream>

int main()
{
unsigned short width = 10;
short x = 2;
std::cout << (x - width);
return 0;
}

--
Erik Wikström
 
Reply With Quote
 
 
 
 
Chris Gordon-Smith
Guest
Posts: n/a
 
      06-07-2008
Juha Nieminen wrote:

> I was once taught that if some integral value can never have negative
> values, it's a good style to use an 'unsigned' type for that: It's
> informative, self-documenting, and you are not wasting half of the value
> range for values which you will never be using.
>
> I agreed with this, and started to always use 'unsigned' whenever
> negative values wouldn't make any sense. I did this for years.
>
> However, I slowly changed my mind: Doing this often causes more
> problems than it's worth. A good example:
>
> If you have an image class, its width and height properties can
> *never* get negative values. They will always be positive. So it makes
> sense to use 'unsigned' for the width and height, doesn't it? What
> problems could that ever create?
>
> Well, assume that you are drawing images on screen, by pixel
> coordinates, and these images can be partially (or completely) outside
> the screen. For example, the left edge coordinate of the image to be
> drawn might have a negative x value (for example drawing a 100x100 image
> at coordinates <-20, 50>). Since the coordinates are signed and the
> dimensions of the image are unsigned, this may cause signed-unsigned
> mixup. For example this:
>
> if(x - width/2 < 1) ...
>
> where 'x' is a signed integer, gives *different* results depending on
> whether 'width' is signed or unsigned, with certain values of those
> variables (for example x=2 and width=10). The intention is to treat
> 'width' here as a signed value, but if it isn't, the comparison will
> malfunction (without explicitly casting 'width' to a signed value). This
> may well go completely unnoticed because compilers might not even give
> any warning (for example gcc doesn't).
>
> Thus at some point I started to *always* use signed integers unless
> there was a very good reason not to. (Of course this sometimes causes
> small annoyances because STL containers return an unsigned value for
> their size() functions, but that's usually not a big problem.)
>
> It would be interesting to hear other opinions on this subject.


Yes, I have had similar experiences / thoughts.

Some while back I thought it would be a good idea to use unsigned integers.
I don't think I read anywhere that this is good practice, and as a spare
time programmer I have never been on a C++ course; it just seemed 'obvious'
that using unsigned for values that can never be negative would be safer.

So I tried using unsigned integers in my simulation project. However I soon
started finding that I was getting compiler warnings about unsigned /
signed conversions. When I started trying to change more variables to
unsigned to stop the warnings, I just started getting more warnings.

I pretty soon abandoned the whole thing on the basis that it was more
trouble than it was worth (but also feeing slightly guilty).

I supposed that part of the problem might have been that I was trying to
retro-fit existing code, rather than coding from the outset to use
unsigned. However, the example given by Juha above makes me think that this
is not just a problem of retro-fitting. There seem to be scenarios where
using unsigned int is positively dangerous, particularly in scenarios where
the compiler doesn't generate a warning (and I've just confirmed on my own
gcc setup that there are such scenarios).

Rather than using unsigned, I use Assertions liberally, and having seen the
danger of signed/unsigned conversions, I think this is the right approach.

Chris Gordon-Smith
www.simsoup.info
 
Reply With Quote
 
Chris Forone
Guest
Posts: n/a
 
      06-07-2008
Erik Wikström schrieb:
> On 2008-06-07 12:43, Juha Nieminen wrote:
>> I was once taught that if some integral value can never have negative
>> values, it's a good style to use an 'unsigned' type for that: It's
>> informative, self-documenting, and you are not wasting half of the value
>> range for values which you will never be using.
>>
>> I agreed with this, and started to always use 'unsigned' whenever
>> negative values wouldn't make any sense. I did this for years.
>>
>> However, I slowly changed my mind: Doing this often causes more
>> problems than it's worth. A good example:
>>
>> If you have an image class, its width and height properties can
>> *never* get negative values. They will always be positive. So it makes
>> sense to use 'unsigned' for the width and height, doesn't it? What
>> problems could that ever create?
>>
>> Well, assume that you are drawing images on screen, by pixel
>> coordinates, and these images can be partially (or completely) outside
>> the screen. For example, the left edge coordinate of the image to be
>> drawn might have a negative x value (for example drawing a 100x100 image
>> at coordinates <-20, 50>). Since the coordinates are signed and the
>> dimensions of the image are unsigned, this may cause signed-unsigned
>> mixup. For example this:
>>
>> if(x - width/2 < 1) ...
>>
>> where 'x' is a signed integer, gives *different* results depending on
>> whether 'width' is signed or unsigned, with certain values of those
>> variables (for example x=2 and width=10).

>
> Wow, that was certainly an eye-opener. I had assumed that in this case
> both values would be promoted to some larger type (signed long) which
> could accurately represent both values (the signed and the unsigned int)
> but apparently not.
>
> This is a defect in the standard in my opinion since it allows the
> correct action to be taken for types smaller than int:
>
> #include <iostream>
>
> int main()
> {
> unsigned short width = 10;
> short x = 2;
> std::cout << (x - width);
> return 0;
> }
>


is -8 (gcc 3.4.5/adam riese)...
 
Reply With Quote
 
Darío Griffo
Guest
Posts: n/a
 
      06-07-2008
On Jun 7, 7:43 am, Juha Nieminen <nos...@thanks.invalid> wrote:
> I was once taught that if some integral value can never have negative
> values, it's a good style to use an 'unsigned' type for that: It's
> informative, self-documenting, and you are not wasting half of the value
> range for values which you will never be using.
>
> I agreed with this, and started to always use 'unsigned' whenever
> negative values wouldn't make any sense. I did this for years.
>
> However, I slowly changed my mind: Doing this often causes more
> problems than it's worth. A good example:
>
> If you have an image class, its width and height properties can
> *never* get negative values. They will always be positive. So it makes
> sense to use 'unsigned' for the width and height, doesn't it? What
> problems could that ever create?
>
> Well, assume that you are drawing images on screen, by pixel
> coordinates, and these images can be partially (or completely) outside
> the screen. For example, the left edge coordinate of the image to be
> drawn might have a negative x value (for example drawing a 100x100 image
> at coordinates <-20, 50>). Since the coordinates are signed and the
> dimensions of the image are unsigned, this may cause signed-unsigned
> mixup. For example this:
>
> if(x - width/2 < 1) ...
>
> where 'x' is a signed integer, gives *different* results depending on
> whether 'width' is signed or unsigned, with certain values of those
> variables (for example x=2 and width=10). The intention is to treat
> 'width' here as a signed value, but if it isn't, the comparison will
> malfunction (without explicitly casting 'width' to a signed value). This
> may well go completely unnoticed because compilers might not even give
> any warning (for example gcc doesn't).
>
> Thus at some point I started to *always* use signed integers unless
> there was a very good reason not to. (Of course this sometimes causes
> small annoyances because STL containers return an unsigned value for
> their size() functions, but that's usually not a big problem.)
>
> It would be interesting to hear other opinions on this subject.


It's a good moment for re-read Stroustrups The C++ Programming
Language
He talks about usual conversions un binary operators.
Your example: if(x - width/2 < 1) ...
considering x as int and width as unsigned, should return a unsigned
value.
There are a lot more of basic conversion rules, but i think it fits
here.
I've assumed (until today) the compiler autocast width to signed
before makes the comparison, but it is not true.


About your question, I still think that if the value will never have a
negative value, it should be unsigned, because of the reasons you had
told. The example of the properties of an image is valid, for the
first argument, width and height properties will allways be non
negative, but another thing is to calculate where you're going to draw
them. Where your are going to draw is a coordinate, and they certainly
can be negative, so they have the be signed values. But we where
mixing the concept of a coordinate with a width and height. Booth are
related at drawing time, but not the same thing.

Darío


 
Reply With Quote
 
Tomás Ó hÉilidhe
Guest
Posts: n/a
 
      06-07-2008
On Jun 7, 11:43*am, Juha Nieminen <nos...@thanks.invalid> wrote:

> * If you have an image class, its width and height properties can
> *never* get negative values. They will always be positive. So it makes
> sense to use 'unsigned' for the width and height, doesn't it? What
> problems could that ever create?
>
> * Well, assume that you are drawing images on screen, by pixel
> coordinates, and these images can be partially (or completely) outside
> the screen. For example, the left edge coordinate of the image to be
> drawn might have a negative x value (for example drawing a 100x100 image
> at coordinates <-20, 50>).



I agree that this is a case where you'd consider using signed integer
types, but I'm still a stedfast unsigned man. My major peeve with
signed integer types is their undefined behaviour upon overflow.

(Of course the less pretty solution is to use casts in your code)
 
Reply With Quote
 
Erik Wikström
Guest
Posts: n/a
 
      06-07-2008
On 2008-06-07 16:47, Chris Forone wrote:
> Erik Wikström schrieb:
>> On 2008-06-07 12:43, Juha Nieminen wrote:
>>> I was once taught that if some integral value can never have negative
>>> values, it's a good style to use an 'unsigned' type for that: It's
>>> informative, self-documenting, and you are not wasting half of the value
>>> range for values which you will never be using.
>>>
>>> I agreed with this, and started to always use 'unsigned' whenever
>>> negative values wouldn't make any sense. I did this for years.
>>>
>>> However, I slowly changed my mind: Doing this often causes more
>>> problems than it's worth. A good example:
>>>
>>> If you have an image class, its width and height properties can
>>> *never* get negative values. They will always be positive. So it makes
>>> sense to use 'unsigned' for the width and height, doesn't it? What
>>> problems could that ever create?
>>>
>>> Well, assume that you are drawing images on screen, by pixel
>>> coordinates, and these images can be partially (or completely) outside
>>> the screen. For example, the left edge coordinate of the image to be
>>> drawn might have a negative x value (for example drawing a 100x100 image
>>> at coordinates <-20, 50>). Since the coordinates are signed and the
>>> dimensions of the image are unsigned, this may cause signed-unsigned
>>> mixup. For example this:
>>>
>>> if(x - width/2 < 1) ...
>>>
>>> where 'x' is a signed integer, gives *different* results depending on
>>> whether 'width' is signed or unsigned, with certain values of those
>>> variables (for example x=2 and width=10).

>>
>> Wow, that was certainly an eye-opener. I had assumed that in this case
>> both values would be promoted to some larger type (signed long) which
>> could accurately represent both values (the signed and the unsigned int)
>> but apparently not.
>>
>> This is a defect in the standard in my opinion since it allows the
>> correct action to be taken for types smaller than int:
>>
>> #include <iostream>
>>
>> int main()
>> {
>> unsigned short width = 10;
>> short x = 2;
>> std::cout << (x - width);
>> return 0;
>> }
>>

>
> is -8 (gcc 3.4.5/adam riese)...


Exactly, but if you use int instead of short you get 4294967288, because
the unsigned int is not promoted to a signed long.

--
Erik Wikström
 
Reply With Quote
 
Daniel Pitts
Guest
Posts: n/a
 
      06-07-2008
Paavo Helde wrote:
> Tomás Ó hÉilidhe <> kirjutas:
>
>> types, but I'm still a stedfast unsigned man. My major peeve with
>> signed integer types is their undefined behaviour upon overflow.

>
> You mean that you are fond of the following code having no undefined
> behavior? Sorry, I have not encountered a need for this kind of defined
> behavior!
>
> #include <iostream>
>
> int main() {
> unsigned int a = 2150000000u;
> unsigned int b = 2160000000u;
> unsigned int c = (a+b)/2;
>
> std::cout << "a=" << a << "\nb=" << b <<
> "\nand their average\nc=" << c << "\n";
> }
>
> Output (32-bit unsigned ints):
>
> a=2150000000
> b=2160000000
> and their average
> c=7516352
>
> The unsigned integers in C/C++ are very specific cyclic types with
> strange overflow and wrapping rules. IMHO, these should be used primarily
> in some very specific algorithms needing such cyclic types.
>
> Regards
> Paavo

I don't have a copy of the standard, but does the standard actually
define unsigned integral types as having that overflow behavior? Or is
that just the "most common case"?

I'm not questioning to make a point, I really would like to know the answer.

Thanks,
Daniel.

--
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
 
Reply With Quote
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      06-07-2008
Daniel Pitts wrote:

> Paavo Helde wrote:
>> Tomás Ó hÉilidhe <> kirjutas:
>>
>>> types, but I'm still a stedfast unsigned man. My major peeve with
>>> signed integer types is their undefined behaviour upon overflow.

>>
>> You mean that you are fond of the following code having no undefined
>> behavior? Sorry, I have not encountered a need for this kind of defined
>> behavior!
>>
>> #include <iostream>
>>
>> int main() {
>> unsigned int a = 2150000000u;
>> unsigned int b = 2160000000u;
>> unsigned int c = (a+b)/2;
>>
>> std::cout << "a=" << a << "\nb=" << b <<
>> "\nand their average\nc=" << c << "\n";
>> }
>>
>> Output (32-bit unsigned ints):
>>
>> a=2150000000
>> b=2160000000
>> and their average
>> c=7516352
>>
>> The unsigned integers in C/C++ are very specific cyclic types with
>> strange overflow and wrapping rules. IMHO, these should be used primarily
>> in some very specific algorithms needing such cyclic types.

[snip]

The wrapping isn't all that strange.


> I don't have a copy of the standard, but does the standard actually
> define unsigned integral types as having that overflow behavior? Or is
> that just the "most common case"?
>
> I'm not questioning to make a point, I really would like to know the
> answer.


Overflow for signed arithmetic types is undefined behavior [5/5]. Unsigned
integer types have arithmetic mod 2^N where N is a the bitlength [3.9.1/4].


Best

Kai-Uwe Bux
 
Reply With Quote
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      06-07-2008
Paavo Helde wrote:

> Daniel Pitts <> kirjutas:
>
>> Paavo Helde wrote:
>>> Tomás Ó hÉilidhe <> kirjutas:
>>>
>>>> types, but I'm still a stedfast unsigned man. My major peeve with
>>>> signed integer types is their undefined behaviour upon overflow.
>>>
>>> You mean that you are fond of the following code having no undefined
>>> behavior? Sorry, I have not encountered a need for this kind of
>>> defined behavior!
>>>
>>> #include <iostream>
>>>
>>> int main() {
>>> unsigned int a = 2150000000u;
>>> unsigned int b = 2160000000u;
>>> unsigned int c = (a+b)/2;
>>>
>>> std::cout << "a=" << a << "\nb=" << b <<
>>> "\nand their average\nc=" << c << "\n";
>>> }
>>>
>>> Output (32-bit unsigned ints):
>>>
>>> a=2150000000
>>> b=2160000000
>>> and their average
>>> c=7516352
>>>
>>> The unsigned integers in C/C++ are very specific cyclic types with
>>> strange overflow and wrapping rules. IMHO, these should be used
>>> primarily in some very specific algorithms needing such cyclic types.
>>>
>>> Regards
>>> Paavo

>> I don't have a copy of the standard, but does the standard actually
>> define unsigned integral types as having that overflow behavior? Or is
>> that just the "most common case"?
>>
>> I'm not questioning to make a point, I really would like to know the
>> answer.
>>
>> Thanks,
>> Daniel.

>
> AFAIK the unsigned arithmetics is specified exactly by the standard. This
> means for example that a debug implementation cannot detect and assert the
> overflow, but has to produce the wrapped result instead:
>
> <quote>
>
> 3.9.1/4:
>
> Unsigned integers, declared unsigned, shall obey the laws of arithmetic
> modulo 2^n where n is the number of bits in the value representation of
> that particular size of integer.
>
> Footnote: This implies that unsigned arithmetic does not overflow because
> a result that cannot be represented by the resulting unsigned integer type
> is reduced modulo the number that is one greater than the largest value
> that can be represented by the resulting unsigned integer
> type.
>
> </quote>
>
> In the above example one should also consider the effects of integral
> promotion - the internal calculations are done in unsigned int, which
> means that a similar example with unsigned shorts or chars would appear to
> work correctly. However, I am not sure where the standard says that
> 3.9.1/4 can be violated by promoting the operands to a larger type.


[5.9]

> By considering 3.9.1/4 only it seems that one should have:
>
> unsigned char a=128u, b=128u, c=(a+b)/2; assert(c==0);
>
> Fortunately, this is not the case with my compilers


I am not so sure whether we are really fortunate to have integral
promotions.


Best

Kai-Uwe Bux
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
mod operator for signed integers dr.oktopus C Programming 12 04-10-2011 12:47 PM
Do saturating integers solve the "signed vs. unsigned" debate? joe C++ 21 09-21-2010 05:04 AM
comparing signed and unsigned integers Joe Van Dyk C Programming 3 06-25-2006 09:11 PM
operator % and signed integers Thomas Matthews C++ 8 12-28-2005 05:33 PM
operator % and signed integers Thomas Matthews C Programming 9 12-28-2005 05:33 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57