Negative values in unsigned int

U

Urs Thuermann

I wasn't able to find an answer to the following questions in a draft
version of IOS 9899-99. What is the semantic when you decrement an
unsigned int below 0 (or subtract two unsigned ints with negative
result)? AFAIR, this results in implementation-defined behavior but
not undefined behavior. Is that correct?

So what does the standard say to this code?

void f(void)
{
unsigned int n = 0;
n--;
}

Also, do I have implementation-defined or undefined behavior, if I
decrement below zero but don't use the value, as in the following
code?

void f(unsigned int n)
{
while (n-- > 0) { /* In the last loop iteration, n is
; decremented from 0, but not used
} afterwards */
}

A short notice with section number in the standard would be nice
(as I think section numbering in my draft version is not that
different).

urs
 
V

viza

So what does the standard say to this code?
unsigned int n = 0;
n--;

Always results in UINT_MAX.
Also, do I have implementation-defined or undefined behavior, if I
decrement below zero but don't use the value, as in the following code?

void f(unsigned int n)
{
while (n-- > 0) { /* In the last loop iteration, n is
; decremented from 0, but not used
} afterwards */
}

This evaluates the greater-than with the original value of n, then
decrements n. n is automatic so its value is lost when the function
returns.
 
V

viza

So what does the standard say to this code?
unsigned int n = 0;
n--;

Always results in UINT_MAX.
Also, do I have implementation-defined or undefined behavior, if I
decrement below zero but don't use the value, as in the following code?

void f(unsigned int n)
{
while (n-- > 0) { /* In the last loop iteration, n is
; decremented from 0, but not used
} afterwards */
}

This evaluates the greater-than with the original value of n, then
decrements n. n is automatic so its value is lost when the function
returns.
 
J

jameskuyper

Urs said:
I wasn't able to find an answer to the following questions in a draft
version of IOS 9899-99. What is the semantic when you decrement an
unsigned int below 0 (or subtract two unsigned ints with negative
result)? AFAIR, this results in implementation-defined behavior but
not undefined behavior. Is that correct?

No. It is standard-defined behavior. Section 6.2.5p9 says:

"A computation involving unsigned operands can never 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 type."
So what does the standard say to this code?

void f(void)
{
unsigned int n = 0;
n--;

At this point, the value of n must be UINT_MAX.
}

Also, do I have implementation-defined or undefined behavior, if I
decrement below zero but don't use the value, as in the following
code?

void f(unsigned int n)
{
while (n-- > 0) { /* In the last loop iteration, n is
; decremented from 0, but not used
} afterwards */
}

Since the behavior is standard-defined, you don't have to worry about
it; whether or not the resulting value gets used doesn't matter. If
the behavior were undefined (as, for example, INT_MAX+1), then the
fact that you didn't use the result still wouldn't protect your code,
at least in principle. As a practical matter, since the value is not
used, an optimizing compiler might remove the calculation that
produced the value, reducing the opportunities for undesireable
consequences - but you should never write code which relies upon this.
 
C

CBFalconer

Urs said:
I wasn't able to find an answer to the following questions in a
draft version of IOS 9899-99. What is the semantic when you
decrement an unsigned int below 0 (or subtract two unsigned ints
with negative result)? AFAIR, this results in implementation-
defined behavior but not undefined behavior. Is that correct?

No. It is carefully defined. Unsigned quantities do arithmetic
modulo the (maximum unsigned value + 1).
 
B

Ben Bacarisse

Urs Thuermann said:
I wasn't able to find an answer to the following questions in a draft
version of IOS 9899-99.
A short notice with section number in the standard would be nice
(as I think section numbering in my draft version is not that
different).

Mostly answered except for this bit. The main rule at work is 6.3.1.3
paragraph 2.
 
B

Barry Schwarz

Note the part beginning "the largest value ...". That
value is implementation-defined, hence the value of the
result is implementation-defined.

The value is implementation defined but the behavior is not. The
behavior is defined as quoted. Your approach would also render the
behavior of
int x = '0' < '1';
is also implementation defined since the values of '0' and '1' are
implementation dependent.
 
J

James Kuyper

Eric said:
Note the part beginning "the largest value ...". That
value is implementation-defined, hence the value of the
result is implementation-defined.

No, that's implementation-dependent result, but not
implementation-defined behavior. The implementation gets to decide for
each unsigned type what the value of TYPE_MAX is. Having made that
decision, they get no additional freedom in the value that results from
overflow or underflow for unsigned; there's a standard-defined
relationship between the two values.
 
C

CBFalconer

Barry said:
.... snip ...

The value is implementation defined but the behavior is not. The
behavior is defined as quoted. Your approach would also render
the behavior of
int x = '0' < '1';
is also implementation defined since the values of '0' and '1'
are implementation dependent.

However since '1' is known to have the value ('0' + 1) that x is
thoroughly defined. If you picked 'a' and 'b' I could agree.
 
J

James Kuyper

Eric said:
The disagreement hinges on whether the "result" is part of
the "behavior." It seems flat-out obvious to me that it is,
but you and some others feel it isn't.

An implementation-defined result is a special case of
implementation-defined behavior. Saying "implementation-defined
behavior" is, in many contexts, insufficiently specific for those cases
where the only freedom the standard gives an implementation is the value
of the result. When the standard doesn't even give an implementation
that much freedom; when the value of the result is absolutely
constrained by the standard to bear a particular relationship to some
other implementation-defined value (like TYPE_MAX for an unsigned type),
then even "implementation-defined result" is inappropriate.
The Standard uses "result" and its derivatives freely, but
offers no definition (except maybe by way of ISO/IEC 2382−1,
which I don't have). But 3.4.1p2 says of implementation-
defined behavior:

"An example of implementation-defined behavior is the
propagation of the high-order bit when a signed integer
is shifted right."

Examples are non-normative, but strongly suggestive. This one
suggests that

int i = -1;
i >>= 1;

exhibits "implementation-defined behavior," even though the only
thing that's implementation-defined is the final value of `i',
the result of the computation (6.5.7p5). I rest my case on
non-normative ground, but I rest it anyhow. Harrumph.

The difference is that for unsigned integer types, implementations have
no such freedom. We're discussing code like the following:

unsigned int u = 0;
u--;

For which the implementation, having already decided what the value for
UINT_MAX will be, has absolutely no additional freedom to choose what
the resulting value of u will be; it must be UINT_MAX.
 
K

Keith Thompson

Eric Sosman said:
The disagreement hinges on whether the "result" is part of
the "behavior." It seems flat-out obvious to me that it is,
but you and some others feel it isn't.

The Standard uses "result" and its derivatives freely, but
offers no definition (except maybe by way of ISO/IEC 2382−1,
which I don't have). But 3.4.1p2 says of implementation-
defined behavior:

"An example of implementation-defined behavior is the
propagation of the high-order bit when a signed integer
is shifted right."

Examples are non-normative, but strongly suggestive. This one
suggests that

int i = -1;
i >>= 1;

exhibits "implementation-defined behavior," even though the only
thing that's implementation-defined is the final value of `i',
the result of the computation (6.5.7p5). I rest my case on
non-normative ground, but I rest it anyhow. Harrumph.

The standard defined "behavior" as "external appearance or action"
(C99 3.4).

A program that produces an implementation-defined result produces
implementation-defined behavior only if its visible behavior (e.g.,
output) actually depends on that result.
 
U

Urs Thuermann

No. It is standard-defined behavior. Section 6.2.5p9 says:

"A computation involving unsigned operands can never 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 type."

OK, Thanx. I've read the 1989 edition of the standard 10 or so years
ago and I had in mind that this would result in implementation-defined
behavior, but I probably confused that with the signed integer case
(which also is not implementation-defined but undefined if I read the
the standard correctly).
Since the behavior is standard-defined, you don't have to worry about
it; whether or not the resulting value gets used doesn't matter. If
the behavior were undefined (as, for example, INT_MAX+1), then the
fact that you didn't use the result still wouldn't protect your code,
at least in principle.

Yes, that is what I assumed also.
As a practical matter, since the value is not used, an optimizing
compiler might remove the calculation that produced the value,
reducing the opportunities for undesireable consequences - but you
should never write code which relies upon this.

Yes, of course. I had a function which does somthing similar to

void f(int n)
{
while (--n >= 0)
do_something();
}

and I wanted to change the parameter n to unsigned int like this

void f(unsigned int n)
{
while (n-- > 0)
do_something();
}

and then I wondered what happens when n is 0 in the last loop
iteration. But your answer did clarify this completely, thanks
again.

urs
 
B

Barry Schwarz

OK, Thanx. I've read the 1989 edition of the standard 10 or so years
ago and I had in mind that this would result in implementation-defined
behavior, but I probably confused that with the signed integer case
(which also is not implementation-defined but undefined if I read the
the standard correctly).

It was in C89 but no longer in C99.
 
K

Keith Thompson

Barry Schwarz said:
It was in C89 but no longer in C99.

It's undefined in both C89/C90 and C99.

C99 6.5p5:

If an _exceptional condition_ occurs during the evaluation of an
expression (that is, if the result is not mathematically defined
or not in the range of representable values for its type), the
behavior is undefined.

C90 has the same wording.

Perhaps you're thinking of C99's change in the semantics of
conversions. In C99, a conversion to a signed type of a value that
can't be represented in that type either yields an
implementation-defined result or raises an implementation-defined
signal (C99 6.3.1.3p3); in C90, the result is implementation-defined
(it couldn't raise a signal).

(Out-of-range conversions to a floating-point type invoke undefined
behavior in both C90 and C99.)
 
B

Barry Schwarz

It's undefined in both C89/C90 and C99.

C99 6.5p5:

If an _exceptional condition_ occurs during the evaluation of an
expression (that is, if the result is not mathematically defined
or not in the range of representable values for its type), the
behavior is undefined.

C90 has the same wording.

Perhaps you're thinking of C99's change in the semantics of
conversions. In C99, a conversion to a signed type of a value that
can't be represented in that type either yields an
implementation-defined result or raises an implementation-defined
signal (C99 6.3.1.3p3); in C90, the result is implementation-defined
(it couldn't raise a signal).

(Out-of-range conversions to a floating-point type invoke undefined
behavior in both C90 and C99.)

But the thread (or at least what I could see of it) appeared to be
talking about converting an unsigned value to a signed integer and for
C99 the relevant paragraph seems to be 6.3.1.3-3 which says
"Otherwise, the new type is signed and the value cannot be represented
in it; either the result is implementation-defined or an
implementation-defined signal is raised."
 
K

Keith Thompson

Barry Schwarz said:
Barry Schwarz said:
On 17 Sep 2008 09:58:28 +0200, Urs Thuermann <[email protected]>
wrote: [...]
OK, Thanx. I've read the 1989 edition of the standard 10 or so years
ago and I had in mind that this would result in implementation-defined
behavior, but I probably confused that with the signed integer case
(which also is not implementation-defined but undefined if I read the
the standard correctly).

It was in C89 but no longer in C99.

It's undefined in both C89/C90 and C99.

C99 6.5p5:

If an _exceptional condition_ occurs during the evaluation of an
expression (that is, if the result is not mathematically defined
or not in the range of representable values for its type), the
behavior is undefined.

C90 has the same wording.

Perhaps you're thinking of C99's change in the semantics of
conversions. In C99, a conversion to a signed type of a value that
can't be represented in that type either yields an
implementation-defined result or raises an implementation-defined
signal (C99 6.3.1.3p3); in C90, the result is implementation-defined
(it couldn't raise a signal).

(Out-of-range conversions to a floating-point type invoke undefined
behavior in both C90 and C99.)

But the thread (or at least what I could see of it) appeared to be
talking about converting an unsigned value to a signed integer and for
C99 the relevant paragraph seems to be 6.3.1.3-3 which says
"Otherwise, the new type is signed and the value cannot be represented
in it; either the result is implementation-defined or an
implementation-defined signal is raised."

Then I'm unclear on what you meant by "It was in C89 but no longer in
C99." I thought you meant that something (out-of-range conversion to
a signed type, probably) was undefined in C89, but is no longer
undefined in C99, which is not the case.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,223
Latest member
Jurgen2087

Latest Threads

Top