Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why is this

76 views
Skip to first unread message

Bint

unread,
Oct 1, 2014, 1:30:01 PM10/1/14
to
Can someone explain why I get this result? In the 'if' statement below, I'm
evaluating (0 - (384 % 64)) and it is passing the greater-than-zero test.

int A = 0;
int B = 64;
unsigned long C = 500;

if ((A - (C % B)) > 0)
C += (A - (C % B)); // it gets to here -- why?

500 % 64 is 52, and 0 - 52 is not greater than zero.
Is it somehow because of the an unsigned long?

Thanks,
B

Victor Bazarov

unread,
Oct 1, 2014, 1:42:08 PM10/1/14
to
Likely. Have you tried declaring C just 'long'? Does it make a difference?

V
--
I do not respond to top-posted replies, please don't ask

Justin Bates

unread,
Oct 1, 2014, 1:46:07 PM10/1/14
to
Victor Bazarov wrote:

>> int A = 0;
>> int B = 64;
>> unsigned long C = 500;
>>
>> if ((A - (C % B)) > 0)
>> C += (A - (C % B)); // it gets to here -- why?

Makes no sense adding a negative to an unsigned. It would be converted/
inverted if this were the case.

Paavo Helde

unread,
Oct 1, 2014, 1:51:52 PM10/1/14
to
Bint <bi...@ign.com> wrote in news:D051A43E.F5B8%bi...@ign.com:
Yes, an unsigned type will turn the whole subexpression unsigned, together
with all the nice misfeatures like legalized wrap-around and type tainting.
Better to avoid mixing signed and unsigned in such expressions. And look up
boost::numeric_cast<>.

Beware that there are two parties in this group, ones who think that
unsigned types are the Right Thing, and others who think they are Real
Evil. I predict another 500 posts in this thread ;-(

Cheers
Paavo

Victor Bazarov

unread,
Oct 1, 2014, 2:07:19 PM10/1/14
to
Please consider replying to (and attributing) the original post next
time you wanted to comment on the original post. Thanks!

Mr Flibble

unread,
Oct 1, 2014, 2:42:04 PM10/1/14
to
If a value can never be negative as it represents a "size" or a "count"
for example then using an unsigned type to represent it is perfectly
fine. std::size_t pervades the Standard Libray thanks to std::allocator
and it is unsigned.

/Flibble

Bint

unread,
Oct 1, 2014, 4:05:42 PM10/1/14
to
Boy, that makes no sense to me. I mean, I understand that an unsigned value
can never be negative, but if you throw it into a calculation with signed
values then it should just be treated as a positive value. Let the left
side of the equation determine whether the result can be negative or
positive. I can't believe that's how C works, that it forces the whole
expression to be unsigned! That's crazy, man!


Victor Bazarov

unread,
Oct 1, 2014, 4:22:42 PM10/1/14
to
Which part?

> I mean, I understand that an unsigned value
> can never be negative, but if you throw it into a calculation with signed
> values then it should just be treated as a positive value.

And it is.

> Let the left
> side of the equation determine whether the result can be negative or
> positive.

And in your case what is the "left side"?

> I can't believe that's how C works, that it forces the whole
> expression to be unsigned! That's crazy, man!

Are you in jest? I can't believe you can't believe it.

There are old rules about promotions and conversions of arithmetic types
(integral and floating point) in both C and C++, they are essentially
the same. There is nothing to believe, really, you just need to learn
them. And as you learn them you might just understand the logic behind
them. Eventually.

Gert-Jan de Vos

unread,
Oct 1, 2014, 4:29:51 PM10/1/14
to
On Wednesday, 1 October 2014 19:51:52 UTC+2, Paavo Helde wrote:

> Beware that there are two parties in this group, ones who think that
> unsigned types are the Right Thing, and others who think they are Real
> Evil. I predict another 500 posts in this thread ;-(

The problem is not with the unsigned types. The problem is the conversion
of mixed signed/unsigned expressions to unsigned that C++ inherited
from C. In practice, unsigned types don't behave so nice in arithmetic
expression where they often lead to unexpected wrap arounds.

Consider the difference of two unsigned values. The result will also be
unsigned whereas the arithmetic result can be negative.

I use unsigned for bit manipulation only and convert between unsigned
and int on API boundaries like container's size(). This has kept my code
free of mixed signed/unsigned trouble.

peter koch

unread,
Oct 1, 2014, 4:33:26 PM10/1/14
to
No it's not. Some rule (inherited from C, so it is not going to change) has to be there. C++ does not overload based on "what is on the left side". For one thing, "what is on the left side" does not always exist - e.g.

void f(unsigned);
void f(int);

unsigned i;
int j;

f(i + j);

Which f do you call?

You have learnt a lesson: do not mix signed and unsigned integral values. If I were you, I would avoid the unsigned types. I use them mostly for low-level stuff - e.g. working with "raw" data and bits.
It is an open debate whether the standard library should have used signed or unsigned types e.g. when indexing a std::vector. Today I believe that signed types would be a better choice, but back then with the segmented architecture used for the popular x86 processors then, I would also have chosen an unsigned value.

/Peter

Barry Schwarz

unread,
Oct 1, 2014, 4:53:10 PM10/1/14
to
You should note that your assumption that the code evaluated 0-52 is
wrong. It evaluated 0-52UL which is something different.

When at least one of the operands of an arithmetic operator has rank
greater than int, the expression is evaluated at the highest rank
present. So C%B is evaluated as unsigned long. Then A-(C%B) is also
evaluated as unsigned long. Since C%B is not 0, the difference is not
0. Since unsigned cannot be less than 0, the only remaining option is
greater than 0.

If you change C to unsigned int, a different set of rules would
produce the same result.

--
Remove del for email

Martijn Lievaart

unread,
Oct 1, 2014, 5:45:14 PM10/1/14
to
On Wed, 01 Oct 2014 13:29:39 -0700, Gert-Jan de Vos wrote:

> On Wednesday, 1 October 2014 19:51:52 UTC+2, Paavo Helde wrote:
>
>> Beware that there are two parties in this group, ones who think that
>> unsigned types are the Right Thing, and others who think they are Real
>> Evil. I predict another 500 posts in this thread ;-(

Seems you were right.

> The problem is not with the unsigned types. The problem is the
> conversion of mixed signed/unsigned expressions to unsigned that C++

Right.

> inherited from C. In practice, unsigned types don't behave so nice in
> arithmetic expression where they often lead to unexpected wrap arounds.

And such wrap around is defined, unlike signed types, which also suffer
from wrap around.

> Consider the difference of two unsigned values. The result will also be
> unsigned whereas the arithmetic result can be negative.

Consider the sum of two signed positive vales. The result can be negative
whereas the arithmetic result should be positive.

What you are probably trying to say, is that the difference between two
unsigned integers, lets say indexes into an array, can wrap instead of
becoming negative. On a twos complement machine, this will give the
correct result if assigned to a signed integer of the same size. However,
this behavior is not guaranteed by the standard.

Or in other words, the difference between two unsigned integrals may not
be represented correctly, even when that difference is cast to a signed
type.

> I use unsigned for bit manipulation only and convert between unsigned
> and int on API boundaries like container's size(). This has kept my code
> free of mixed signed/unsigned trouble.

Absolutely sound advice.

M4

Jorgen Grahn

unread,
Oct 1, 2014, 6:26:19 PM10/1/14
to
On Wed, 2014-10-01, Martijn Lievaart wrote:
> On Wed, 01 Oct 2014 13:29:39 -0700, Gert-Jan de Vos wrote:
...
>> I use unsigned for bit manipulation only and convert between unsigned
>> and int on API boundaries like container's size(). This has kept my code
>> free of mixed signed/unsigned trouble.
>
> Absolutely sound advice.

But like someone mentioned upthread, opinions on that differ
in c.l.c++, and there have been several long flame wars about it.

Disclaimer: I'm in the other camp.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Scott Lurndal

unread,
Oct 2, 2014, 10:38:13 AM10/2/14
to
peter koch <peter.ko...@gmail.com> writes:
>Den onsdag den 1. oktober 2014 22.05.42 UTC+2 skrev Bint:

>It is an open debate whether the standard library should have used signed o=
>r unsigned types e.g. when indexing a std::vector.

> Today I believe that sig=
>ned types would be a better choice, but back then with the segmented archit=
>ecture used for the popular x86 processors then, I would also have chosen a=
>n unsigned value.

std::vector was introduced almost a decade after the i386 added flat
addressing modes and every relevent operating system switched away from
segmentation, even Windows.

While C compiled for for the PDP-11 segmented architecture, it wasn't
designed around a segmented architecture. And there was never a unix
system that used x86 segments (other than the obligitory CS/DS/GDT required
to use linear addressing on x86).

I generally use unsigned for everything, unless negative values are
legal in context. For example, if I'm representing a physical or virtual
address, the type must be unsigned; size_t is the correct type for
counts of objects, bytes, etc. ssize_t should only be used for return
values from certain system calls that return -1 on error (IIRC, ssize_t
was originally only defined over [-1...MAXINT]).
0 new messages