compare a large number of variables

M

Mark B

Wow, I thought this part of the thread died a week ago with my last post...
took you long enough to respond
(btw: was out friday and don't work weekends which is why it took me a few
days to respond :)

Tim Rentsch said:
Mark said:
Tim Rentsch said:
[snip]
As far as I understand, overflow/underflow invokes behaviour not
covered
by the standard, which may include setting all bits to zero.

I thought it was covered... no?

H.2.2 Integer types
[#1] The signed C integer types int, long int, long long
int, and the corresponding unsigned types are compatible
with LIA-1. If an implementation adds support for the LIA-1
exceptional values integer_overflow and undefined, then
those types are LIA-1 conformant types. C's unsigned
integer types are ``modulo'' in the LIA-1 sense in that
overflows or out-of-bounds results silently wrap. An
implementation that defines signed integer types as also
being modulo need not detect integer overflow, in which
case, only integer divide-by-zero need be detected.

Maybe I'm misreading something...

First: Appendix H is informative rather than normative.

Second: The paragraph above only says that signed integer
types *may* behave in a certain way
No, it also states that unsigned integer types DO behave a certain
way.

The subject in question is overflow (or underflow), which
usually is understood to refer to signed integer types rather
than unsigned integer types.
Then why are we having this discussion?

Apparently, because you haven't been able to express
yourself clearly, because you respond to what you imagine
people are saying rather than what they actually do say, and
because you make statements that either are poorly worded or
just plain wrong;
Touche.

and also because I've been optimistic
enough to think that one or more of those might change
sometime soon.

Possibly. Though I am not a pedant so I do sometimes respond
to what I perceive people to 'mean' rather than what they actually
do say... but that can be a good thing! Too many posters on clc
get blasted for not phrasing their legitimate questions appropriately...
while others can get their homework problems completed within
minutes as long as they word their posts properly! clc might be
a better place if some of the pedants were a little more lenient.
The comment I think you're referring to is one you made in
an earlier post that isn't quoted above; namely:


As written this statement is wrong. The expression in the
'if' certainly can overflow. It also can result in
undefined behavior even if the subtraction operators don't
result in overflow.

I must be missing something... how can it result in
undefined behavior with no overflow?
If you meant to say, "this expression can't result in
overflow, because the operands are 'unsigned'", there's
nothing to support that statement. In no posting in the
thread were any variables declared having any unsigned
integer type.

Correct, not one post in this particular branch of the thread
had ever declared any of the variables.
On the other hand, several postings did
declare variables of *signed* integer type, including
variables that participated in the comparison (as might be
represented by a,b,c, etc, in the 'if' above).

Check again, maybe else-thread, but not in this particular
branch.
If you meant to say, "this expression can't result in
overflow, because the '|' operators mean the values must be
unsigned", that's wrong.
If you meant to say, "as long as the variables are of some
unsigned integer type, overflow can't happen", that may be
true, but not really very relevant, since there still is
the possibility of undefined behavior.
How?

If you meant to say, "*if* the operands are all of type
'unsigned int', then no overflow or undefined behavior can
occur", that's true, but then why didn't you just say that?

I thought I did... by posting what I thought to be the relevent
section from the (draft) standard.
And then again when I responded to your rebuttal with:
No, it also states that unsigned integer types DO behave a certain way.
There is nothing in your posting (the one that has the
excerpt above) that says anything about any unsigned type,
let along 'unsigned int', either in your text or what was
included from other posters. Nor does your earlier posting
(the original one that has the 'if(a-b|...' in it) say
anything about any unsigned type.

None of the earlier posts specified ANY type.
Follow this thread back to the OP and you'll see that.
You may imagine that the operands were "bit operands", but
there is nothing in what you wrote to indicate that;

<q>No, it also states that unsigned integer types DO behave a certain
way. said:
and,
to the contrary in earlier postings when variables were
declared as 'int' rather than 'unsigned int'.

You keep referring to this earlier post in which the
variables were declared... maybe my newsreader missed a
few messages... whose post, and when? Maybe I'll be able
to find it using google, because I certainly didn't get it here.
[snip]>

In my document [ISO/IEC 9899:1999 (E)], 3.18 is a definition of
the ceiling function.
Impossible, there is no such function in the C language. [snip]

It's not only possible, if you get a copy of the C standard
document mentioned above, you'll see that it's true.

Am I the only poster in clc using the draft?
I'm suprised to find that they've added a function they don't
mention in the final draft... maybe I should spend the $18
to see what else I'm missing :)
You *should* know what I'm reading; the reference number
for the document is given above. Presumably what you meant
to say is that you don't know what text is contained in what
I'm reading, and I expect that's true. But you could find
out by getting a copy of the document and reading it yourself.

Incidentally, note that I said 3.18 is a definition of the
ceiling function, not the 'ceiling' function.

Yes, and I stated that I assumed you were referring to the
'ceil functions' - isn't that still the appropriate terminology?
It is according to the final draft, maybe they changed it between
then and the final version :) Does a word search on 'ceiling'
return anything in the final version of the standard? If so, I may
have to spend the $18 - otherwise the final draft may still do
me just fine.

Actually, the pronunciation of function names may make a
good sub-thread... I haven't seen one of those in a few years!
(then again, I had taken a few years off from comp-lang-c and
only recently returned, maybe I just missed it!)

A)
strcpy = stir copy
ceil = seal
fprintf = ef print ef

B)
strcpy = string copy
ceil = ceiling
fprintf = file print file

I belong to group A.
Which group do you (anyone) prefer? A? B?
I'm sure we'll get a bunch of people making
up their own group 'C' too, let's see them!

Regards,
Mark
 
M

Mark B

Actually, the pronunciation of function names may make a
good sub-thread... I haven't seen one of those in a few years!
(then again, I had taken a few years off from comp-lang-c and
only recently returned, maybe I just missed it!)

A)
strcpy = stir copy
ceil = seal
fprintf = ef print ef

B)
strcpy = string copy
ceil = ceiling
fprintf = file print file

*oops* replace preceding line with:
fprintf = file print formatted
Didn't notice the typo this afternoon,
hope I caught that before anyone else did...
oh well, time will tell.
Guess I'll just let the thread officially die now :)
 
T

Tim Rentsch

Mark B said:
Wow, I thought this part of the thread died a week ago with my last post...
took you long enough to respond
(btw: was out friday and don't work weekends which is why it took me a few
days to respond :)

Yes, real life keeps interfering with the more important
activity of keeping up on comp.lang.c. :)

I'm going to try to trim this down to just the relevant
portions...

Though I am not a pedant so I do sometimes respond
to what I perceive people to 'mean' rather than what they actually
do say...

When you do that it's usually a good idea to make it
explicit, eg, "what I think you mean is ..." and then
proceed from there. Otherwise readers will probably
think you've misunderstood, or worse.

I must be missing something... how can it result in
undefined behavior with no overflow?

unsigned char a = 3, b = 5, c = 8;

if(a-b|b-c) ...

The arguments of 'a-b' and 'b-c' are promoted (assuming
UCHAR_MAX < INT_MAX) to 'int', and the results therefore
are negative, with no overflow. Doing a bitwise OR of
negative operands means undefined behavior; 6.5 p4.

Check again, maybe else-thread, but not in this particular
branch.

Posting by Jack Klein, directly responding to the OP;
not on the path to the root posting by the OP, but it
being a direct response and a few days earlier it seems
reasonable to include.

Posting by Eric Sosman, directly responding to the OP; on
the path to the root from this post. Any posting on the
path to the root seems like it should count as part of
"this branch".

Both of these should be easy to find with google; for
some reason I can't get a citation URL out of google
right now.


See above.

I thought I did... by posting what I thought to be the relevent
section from the (draft) standard.

You may have meant to imply it, but you didn't state it.
It's usually good to remember that people reading what
you post can't read your mind.

None of the earlier posts specified ANY type.
Follow this thread back to the OP and you'll see that.

They did, as I detailed above; one was on the path to
the OP.

<q>No, it also states that unsigned integer types DO behave a certain
way.</q>

The quoted comment is a statement about types. It isn't
a statement about operands. It's important to say what
you mean, directly and explicitly. This really shouldn't
be so hard to understand -- people respond to what you
actually write, not to the thoughts that are in your head.

You keep referring to this earlier post in which the
variables were declared... maybe my newsreader missed a
few messages... whose post, and when? Maybe I'll be able
to find it using google, because I certainly didn't get it here.

After my first statement that there were, you could have
used google to find the postings, and that would have
avoided the confusion. I used google to review the
thread before responding to your earlier comments, to
make sure I hadn't missed something.

In my document [ISO/IEC 9899:1999 (E)], 3.18 is a definition of
the ceiling function.
Impossible, there is no such function in the C language. [snip]

It's not only possible, if you get a copy of the C standard
document mentioned above, you'll see that it's true.

Am I the only poster in clc using the draft?

No; but I do think you're one of the few to make unequivocal
statements about what's in the official version when you
are using just the draft version.

I'm suprised to find that they've added a function they don't
mention in the final draft... maybe I should spend the $18
to see what else I'm missing :)

There are at least a few significant differences. I found
it worth my while to get a copy of the official version.

Yes, and I stated that I assumed you were referring to the
'ceil functions' - isn't that still the appropriate terminology?

You did state that, which is why I made a point of making a
clarifying statement. Dave Thompson also explained this in
a separate posting (thank you Dave).

It is according to the final draft, maybe they changed it between
then and the final version :) Does a word search on 'ceiling'
return anything in the final version of the standard? If so, I may
have to spend the $18 - otherwise the final draft may still do
me just fine.

I do recommend getting one. Also, one other recommendation -
try to develop the habit of reading what is written and not
what you presume is meant. Besides getting on better in
the newsgroup, you'll find this habit helpful in reading
the standard document itself.
 
M

Mark B

Tim Rentsch said:
I'm going to try to trim this down to just the relevant
portions...

Although we disagree on what posts are pertinent to a
particular branch, I'll follow your lead and trim even more.
unsigned char a = 3, b = 5, c = 8;
if(a-b|b-c) ...

The arguments of 'a-b' and 'b-c' are promoted (assuming
UCHAR_MAX < INT_MAX) to 'int', and the results therefore
are negative, with no overflow.
OK.

Doing a bitwise OR of
negative operands means undefined behavior; 6.5 p4.

If so, I'm missing something and would appreciate a point in the
right direction. As you know, I'm using the draft... is this what
you are in fact referring to? (if not please post appropriate text)
6.5 Expressions
...
[#4] Some operators (the unary operator ~, and the binary
operators <<, >>, &, ^, and |, collectively described as
bitwise operators) are required to have operands that have
integer type. These operators return values that depend on
the internal representations of integers, and have
implementation-defined and undefined aspects for signed
types.

The 'undefined aspects' are later identified (when applicable) in the
appropriate sections which define the operators individually.
For example, the section describing bitwise shift operators explicitly
states the specific circumstances in which using signed integer types
results in either undefined behavior, or implementation defined behavior.
(both are possible)

I don't see anything in the section which describes the inclusive OR
(6.5.12 in the draft) which cautions against using a negative operand.
The only requirement seems to be that each of the operands have
an integer type. What am I missing (or misinterpreting?)

Respectfully,
Mark
 
D

Dietmar Schindler

Suman said:
#include <stdio.h>
int main(void)
{
int a = 0;
int b = 3, c = 5, d = 2, e = 6;
printf("%d\n", a ? b, c : d, e);
printf("%d\n", a ? (b, c) : (d, e));
printf("%d\n", (a ? (b, c) : d), e);
return 0;
}
gcc version 4.0.0
gcc -W -Wall -std=c99 cond.c
and a few warnings about `left-hand operand of comma expression has no
effect' later ...
<output>
2
6
2
</output>

I have the impression that you are not aware of the first printf
outputting the value of

a ? b, c : d

(which is the same as the last printf), since the comma is not treated
as the operator, but as an argument separator.
 
T

Tim Rentsch

Mark B said:
Although we disagree on what posts are pertinent to a
particular branch, I'll follow your lead and trim even more.

Good man! :)

Doing a bitwise OR of
negative operands means undefined behavior; 6.5 p4.

If so, I'm missing something and would appreciate a point in the
right direction. As you know, I'm using the draft... is this what
you are in fact referring to? (if not please post appropriate text)
6.5 Expressions
...
[#4] Some operators (the unary operator ~, and the binary
operators <<, >>, &, ^, and |, collectively described as
bitwise operators) are required to have operands that have
integer type. These operators return values that depend on
the internal representations of integers, and have
implementation-defined and undefined aspects for signed
types.

The 'undefined aspects' are later identified (when applicable) in the
appropriate sections which define the operators individually.
For example, the section describing bitwise shift operators explicitly
states the specific circumstances in which using signed integer types
results in either undefined behavior, or implementation defined behavior.
(both are possible)

*Sometimes* later identified in 6.5.x; not always.

I don't see anything in the section which describes the inclusive OR
(6.5.12 in the draft) which cautions against using a negative operand.
The only requirement seems to be that each of the operands have
an integer type. What am I missing (or misinterpreting?)

Look at 6.2.6, "Representations of Types". Pay special
attention to "trap representations". The description of
trap representations is so permissive that seems like
bitwise operators on negative operands can result in
undefined behavior at any time. Remember the rule - if
behavior isn't explicitly defined, it's undefined. However,
if that isn't enough, a case of undefined behavior is called
out explicitly in 6.2.6.2 p2,p4. The simple expression

-1|-2

may generate a bit pattern that corresponds to a "negative
zero" (on a ones-complement machine); if the implementation
doesn't support negative zeros, the behavior is undefined.
 
M

Mark B

First, I'd like to thank you for getting involved in this discussion
and enlightening me :) That being said, just a few questions left.
Doing a bitwise OR of
negative operands means undefined behavior; 6.5 p4.

If so, I'm missing something and would appreciate a point in the
right direction. As you know, I'm using the draft... is this what
you are in fact referring to? (if not please post appropriate text)
6.5 Expressions
...
[#4] Some operators (the unary operator ~, and the binary
operators <<, >>, &, ^, and |, collectively described as
bitwise operators) are required to have operands that have
integer type. These operators return values that depend on
the internal representations of integers, and have
implementation-defined and undefined aspects for signed
types.

The 'undefined aspects' are later identified (when applicable) in the
appropriate sections which define the operators individually.
For example, the section describing bitwise shift operators explicitly
states the specific circumstances in which using signed integer types
results in either undefined behavior, or implementation defined behavior.
(both are possible)

*Sometimes* later identified in 6.5.x; not always.

I don't see anything in the section which describes the inclusive OR
(6.5.12 in the draft) which cautions against using a negative operand.
The only requirement seems to be that each of the operands have
an integer type. What am I missing (or misinterpreting?)

Look at 6.2.6, "Representations of Types". Pay special
attention to "trap representations". The description of
trap representations is so permissive that seems like
bitwise operators on negative operands can result in
undefined behavior at any time.

Only if an exception is raised, no? 6.2.6.2 p3 footnote 39
Regardless, no arithmetic operation on valid
values can generate a trap representation other than as
part of an exception such as an overflow, and this cannot
occur with unsigned types.
Remember the rule - if
behavior isn't explicitly defined, it's undefined.

Behavior is often explicitly defined to be undefined.
When I'm trying to determine if something is undefined and I
can't find anything to support that in the Annex, I wonder if
I'm not just missing (or misinterpretting) something elsewhere
in the standard.
However,
if that isn't enough, a case of undefined behavior is called
out explicitly in 6.2.6.2 p2,p4. The simple expression

-1|-2

may generate a bit pattern that corresponds to a "negative
zero" (on a ones-complement machine); if the implementation
doesn't support negative zeros, the behavior is undefined.

That is made clear in Annex F.2.1 :(
Notwithstanding signed zero on a implementation which doesn't
support it - is there any other condition you can think of off the
top of your head (this thread is all but done and you shouldn't
waste too much more time on it - I do see the light ;-) in which
OR'ing negative operands will invoke UB?

Thanks again for taking the time to enlighten me.

Mark
 
T

Tim Rentsch

Mark B said:
First, I'd like to thank you for getting involved in this discussion
and enlightening me :) That being said, just a few questions left.

You're welcome. Your questions are few but mighty. :)

[snip]
I don't see anything in the section which describes the inclusive OR
(6.5.12 in the draft) which cautions against using a negative operand.
The only requirement seems to be that each of the operands have
an integer type. What am I missing (or misinterpreting?)

Look at 6.2.6, "Representations of Types". Pay special
attention to "trap representations". The description of
trap representations is so permissive that seems like
bitwise operators on negative operands can result in
undefined behavior at any time.

Only if an exception is raised, no? 6.2.6.2 p3 footnote 39
Regardless, no arithmetic operation on valid
values can generate a trap representation other than as
part of an exception such as an overflow, and this cannot
occur with unsigned types.

Incidentally, in my document, the text just cited appears in
footnote 44, under 6.2.6.2 p1. There is a corresponding
footnote 45, under 6.2.6.2 p5, for signed integer types.

Also, for clarification - an "exceptional condition" is not
at all the same as "raising an exception". I don't think
you're confused on this point, but in case you were I wanted
to point it out.

An "exceptional condition" occurs any time a "value" that
matches a trap representation is produced. What limits are
there on trap representations? As near as I can tell, there
really aren't any for negative values of signed integer
types. So for example, an 'int' datatype where every 17th
negative "value" is really a trap representation seems to be
allowed by the standard. I admit, such an implementation
would be extraordinarily perverse (not to mention nearly
completely useless), but it seems like it's allowed.

More plausibly, an implementation with four-byte int's that
have INT_MIN == -32767 and INT_MAX == 2147483647, with all
negative "values" between -2147483648 and -32768 being trap
representations, also seems to be allowed. That's not quite
so perverse an implementation.

An implementation with two-byte, two's complement int's,
with INT_MIN == -32767 and INT_MAX == 32767, and -32768
being a trap representation, is explicitly allowed.

Because trap representations aren't restricted as to what
values they can be, any particular value might be a trap
representation; so, generating it would be an "exceptional
condition", because the value can't be represented. There
is a certain amount of circularity in the definition - you
can't generate a trap representation without there being an
exceptional condition, but on the other hand if you ever do
generate a value corresponding to a trap representation then
by definition that's an exceptional condition.

Behavior is often explicitly defined to be undefined.
When I'm trying to determine if something is undefined and I
can't find anything to support that in the Annex, I wonder if
I'm not just missing (or misinterpretting) something elsewhere
in the standard.

I draw your attention to section 4 paragraph 2, where it's
stated explicitly that there is no difference between
behavior specifically labelled as undefined and behavior
whose definition simply doesn't appear - they are both
undefined behavior, with "no difference in emphasis."

I don't like this any better than you do, and I too wonder
at times if there is something I missed or misinterpreted.
Gradually however my confidence has grown, and I feel like
now I have a pretty good idea what's white and what's black,
and where the grey areas are.

That is made clear in Annex F.2.1 :(

Incidentally, be warned - the Annexes in draft versions
are in some cases completely different from the Annexes
in the final (official) version.

Notwithstanding signed zero on a implementation which doesn't
support it - is there any other condition you can think of off the
top of your head (this thread is all but done and you shouldn't
waste too much more time on it - I do see the light ;-) in which
OR'ing negative operands will invoke UB?

As a practical matter, I would expect it never to show up on
any implementations I am likely to encounter, especially on
a machine using two's complement.

At the other end of the spectrum, in some theoretical sense
it might occur any time there are negative operands for
bitwise operators.

In between the two extremes, my guess is that there are some
actual, honest-to-goodness implementations out there that do
something weird (ie, not what I would expect) in such cases.
I don't know what they are; that's part of what makes them
"weird." Because I think such cases are not only permitted
under the standard but reasonably likely to actually exist,
I think it's best to assume that *any* use of negative
operands with bitwise operators should simply be avoided.
So that's what I do.

Thanks again for taking the time to enlighten me.

No problem! Glad my optimism seems to have borne fruit.
 
D

Dietmar Schindler

Tim said:
Look at 6.2.6, "Representations of Types". Pay special
attention to "trap representations". The description of
trap representations is so permissive that seems like
bitwise operators on negative operands can result in
undefined behavior at any time. Remember the rule - if
behavior isn't explicitly defined, it's undefined. However,
if that isn't enough, a case of undefined behavior is called
out explicitly in 6.2.6.2 p2,p4. The simple expression

-1|-2

may generate a bit pattern that corresponds to a "negative
zero" (on a ones-complement machine); if the implementation
doesn't support negative zeros, the behavior is undefined.

6.2.6.1 General

[#8] ... Where a
value is stored in an object using a type that has more than
one object representation for that value, it is unspecified
which representation is used, but a trap representation
shall not be generated.
 
T

Tim Rentsch

Dietmar Schindler said:
Tim said:
Look at 6.2.6, "Representations of Types". Pay special
attention to "trap representations". The description of
trap representations is so permissive that seems like
bitwise operators on negative operands can result in
undefined behavior at any time. Remember the rule - if
behavior isn't explicitly defined, it's undefined. However,
if that isn't enough, a case of undefined behavior is called
out explicitly in 6.2.6.2 p2,p4. The simple expression

-1|-2

may generate a bit pattern that corresponds to a "negative
zero" (on a ones-complement machine); if the implementation
doesn't support negative zeros, the behavior is undefined.

6.2.6.1 General

[#8] ... Where a
value is stored in an object using a type that has more than
one object representation for that value, it is unspecified
which representation is used, but a trap representation
shall not be generated.

In this case the bit pattern that is generated is not a
value, so 6.2.6.1 p8 doesn't apply.
 
D

Dietmar Schindler

Tim said:
Dietmar Schindler said:
Tim said:
... The simple expression

-1|-2

may generate a bit pattern that corresponds to a "negative
zero" (on a ones-complement machine); if the implementation
doesn't support negative zeros, the behavior is undefined.

6.2.6.1 General

[#8] ... Where a
value is stored in an object using a type that has more than
one object representation for that value, it is unspecified
which representation is used, but a trap representation
shall not be generated.

In this case the bit pattern that is generated is not a
value, so 6.2.6.1 p8 doesn't apply.

The assertion "the bit pattern that is generated is not a value" lacks
reasons.

6.5 Expressions

[#1] An expression is a sequence of operators and operands
that specifies computation of a value, or that designates an
object or a function, or that generates side effects, or
that performs a combination thereof.

-1|-2 is an expression that specifies computation of a value.

[#4] Some operators (the unary operator ~, and the binary
operators <<, >>, &, ^, and |, collectively described as
bitwise operators) are required to have operands that have
integer type. These operators return values that depend on
the internal representations of integers, and have
implementation-defined and undefined aspects for signed
types.

The operator | returns a value.
 
T

Tim Rentsch

Dietmar Schindler said:
Tim said:
Dietmar Schindler said:
Tim Rentsch wrote:
... The simple expression

-1|-2

may generate a bit pattern that corresponds to a "negative
zero" (on a ones-complement machine); if the implementation
doesn't support negative zeros, the behavior is undefined.

6.2.6.1 General

[#8] ... Where a
value is stored in an object using a type that has more than
one object representation for that value, it is unspecified
which representation is used, but a trap representation
shall not be generated.

In this case the bit pattern that is generated is not a
value, so 6.2.6.1 p8 doesn't apply.

The assertion "the bit pattern that is generated is not a value" lacks
reasons.

Yes, none were given. I hoped that the statement by itself
would allow you to read the relevant sections and find them
without my having to give further direction.

6.5 Expressions

[#1] An expression is a sequence of operators and operands
that specifies computation of a value, or that designates an
object or a function, or that generates side effects, or
that performs a combination thereof.

Expressions may also result in undefined behavior. The
expression '1/0' normally doesn't generate any value.

-1|-2 is an expression that specifies computation of a value.

[#4] Some operators (the unary operator ~, and the binary
operators <<, >>, &, ^, and |, collectively described as
bitwise operators) are required to have operands that have
integer type. These operators return values that depend on
the internal representations of integers, and have
implementation-defined and undefined aspects for signed
types.

The operator | returns a value.

The bitwise operators, and '|' in particular, also have
"undefined aspects for signed types." When there is
undefined behavior, anything could happen; in particular,
the result of '|' can be a trap representation rather than a
value.

Let's take the particular case of an implementation with
16-bit int's, INT_MIN == -32767, INT_MAX == 32767, using
one's complement, and where an int having all one bits is a
trap representation rather than a value. This possibility
is explicitly allowed by 6.2.6.2 p2. In this implementation,
we would have:

0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
2: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0

-1: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
-2: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1

???: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

The ??? means a trap representation. It is not a value.
Note 6.2.6.1 p5, "Certain object representations need not
represent a value of the object type."

What happens when the expression '-1|-2' is evaluated? The
specification in 6.5.12 p4 is in terms of bits rather than
values:

"The result of the | operator is the bitwise inclusive OR
of the operands (that is, each bit in the result is set
if and only if at least one of the corresponding bits in
the converted operands is set)."

Hence,

-1: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
-2: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1

-1|-2: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

The result is a trap representation, which is not a value.
 
D

Dietmar Schindler

Tim said:
Dietmar Schindler said:
The assertion "the bit pattern that is generated is not a value" lacks
reasons.

Yes, none were given. I hoped that the statement by itself
would allow you to read the relevant sections and find them
without my having to give further direction.
6.5 Expressions

[#1] An expression is a sequence of operators and operands
that specifies computation of a value, or that designates an
object or a function, or that generates side effects, or
that performs a combination thereof.

Expressions may also result in undefined behavior. The
expression '1/0' normally doesn't generate any value.

This example is irrelevant. It is a special case, expressly stated in

6.5.5 Multiplicative operators

Semantics

[#5] The result of the / operator is the quotient from the
division of the first operand by the second; the result of
the % operator is the remainder. In both operations, if the
value of the second operand is zero, the behavior is
undefined.

and one cannot draw general conclusions from a special case.
-1|-2 is an expression that specifies computation of a value.

[#4] Some operators (the unary operator ~, and the binary
operators <<, >>, &, ^, and |, collectively described as
bitwise operators) are required to have operands that have
integer type. These operators return values that depend on
the internal representations of integers, and have
implementation-defined and undefined aspects for signed
types.

The operator | returns a value.

The bitwise operators, and '|' in particular, also have
"undefined aspects for signed types." When there is
undefined behavior, anything could happen; in particular,
the result of '|' can be a trap representation rather than a
value.

...

???: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

The ??? means a trap representation. It is not a value.
Note 6.2.6.1 p5, "Certain object representations need not
represent a value of the object type."

Logic error: "not being a value of the object type" does not imply "not
being a value".
...

-1|-2: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

The result is a trap representation, which is not a value.

All your reasoning here is based on the wrong assumption that a trap
representation were not representing a value.

6.2.6 Representations of types

6.2.6.1 General

[#5] Certain object representations need not represent a
value of the object type. If the stored value of an object
has such a representation ...

Note that the value of an object may have a trap representation.

[#6] ... The values of padding bytes
shall not affect whether the value of such an object is a
trap representation. ... shall similarly not affect
whether the value of such an object is a trap
representation.

Note that the value of an object can be a trap representation.
 
T

Tim Rentsch

Dietmar Schindler said:
Tim said:
Dietmar Schindler said:
The assertion "the bit pattern that is generated is not a value" lacks
reasons.

Yes, none were given. I hoped that the statement by itself
would allow you to read the relevant sections and find them
without my having to give further direction.
6.5 Expressions

[#1] An expression is a sequence of operators and operands
that specifies computation of a value, or that designates an
object or a function, or that generates side effects, or
that performs a combination thereof.

Expressions may also result in undefined behavior. The
expression '1/0' normally doesn't generate any value.

This example is irrelevant. It is a special case, expressly stated in

6.5.5 Multiplicative operators

Semantics

[#5] The result of the / operator is the quotient from the
division of the first operand by the second; the result of
the % operator is the remainder. In both operations, if the
value of the second operand is zero, the behavior is
undefined.

and one cannot draw general conclusions from a special case.
-1|-2 is an expression that specifies computation of a value.

[#4] Some operators (the unary operator ~, and the binary
operators <<, >>, &, ^, and |, collectively described as
bitwise operators) are required to have operands that have
integer type. These operators return values that depend on
the internal representations of integers, and have
implementation-defined and undefined aspects for signed
types.

The operator | returns a value.

The bitwise operators, and '|' in particular, also have
"undefined aspects for signed types." When there is
undefined behavior, anything could happen; in particular,
the result of '|' can be a trap representation rather than a
value.

...

???: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

The ??? means a trap representation. It is not a value.
Note 6.2.6.1 p5, "Certain object representations need not
represent a value of the object type."

Logic error: "not being a value of the object type" does not imply "not
being a value".
...

-1|-2: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

The result is a trap representation, which is not a value.

All your reasoning here is based on the wrong assumption that a trap
representation were not representing a value.

6.2.6 Representations of types

6.2.6.1 General

[#5] Certain object representations need not represent a
value of the object type. If the stored value of an object
has such a representation ...

Note that the value of an object may have a trap representation.

[#6] ... The values of padding bytes
shall not affect whether the value of such an object is a
trap representation. ... shall similarly not affect
whether the value of such an object is a trap
representation.

Note that the value of an object can be a trap representation.

Believe what you want. I'm confident that my conclusion
that undefined behavior may result from expressions like
'-1|-2' is consistent with what the document's authors were
meaning to express when it was written.

If you want to pursue the topic further, comp.std.c may
be a better place to do that.
 
D

Dietmar Schindler

Tim said:
Dietmar Schindler said:
Tim said:
The assertion "the bit pattern that is generated is not a value" lacks
reasons.
...
The bitwise operators, and '|' in particular, also have
"undefined aspects for signed types." When there is
undefined behavior, anything could happen; in particular,
the result of '|' can be a trap representation rather than a
value.

...

???: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

The ??? means a trap representation. It is not a value.
Note 6.2.6.1 p5, "Certain object representations need not
represent a value of the object type."

Logic error: "not being a value of the object type" does not imply "not
being a value".
...

-1|-2: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

The result is a trap representation, which is not a value.

All your reasoning here is based on the wrong assumption that a trap
representation were not representing a value.

6.2.6 Representations of types

6.2.6.1 General

[#5] Certain object representations need not represent a
value of the object type. If the stored value of an object
has such a representation ...

Note that the value of an object may have a trap representation.

[#6] ... The values of padding bytes
shall not affect whether the value of such an object is a
trap representation. ... shall similarly not affect
whether the value of such an object is a trap
representation.

Note that the value of an object can be a trap representation.

Believe what you want. I'm confident that my conclusion
that undefined behavior may result from expressions like
'-1|-2' is consistent with what the document's authors were
meaning to express when it was written.

Should there be any discrepancy between what the authors were meaning to
express and what is written down in the standard, then I think the
written wording would be authoritative, since compiler implementors as
well as most users cannot be expected to be mind readers.
Perhaps you have too little confidence in the standard document's
authors' ability to express themselves.
 
T

Tim Rentsch

Dietmar Schindler said:
Tim said:
[snip][snip]

I'm confident that my conclusion
that undefined behavior may result from expressions like
'-1|-2' is consistent with what the document's authors were
meaning to express when it was written.

Should there be any discrepancy between what the authors were meaning to
express and what is written down in the standard, then I think the
written wording would be authoritative, since compiler implementors as
well as most users cannot be expected to be mind readers.

The written wording should be authoritative, if there is agreement
about what the written wording says. Unfortunately that's not the
case in this discussion.

As used in the C99 document, the term "value" is context dependent.
A particular set of bits can represent a value under one type and
not represent a value under another type. It's impossible to say
whether a given representation is a value or not, without first
knowing the context of what kind of value is being asked about.
(The question also depends on implementation choices of which
representations correspond to values under each particular type.)

Also, the term "value" is used in different senses in the C99
document. The definition of value is stated (in 3.17 p1) as:

precise meaning of the contents of an object when
interpreted as having a particular type

Notice two things about this definition. First, it's impossible
to store a "value" in an object. Objects hold representations,
or if you prefer, bits; they do not hold "meanings" (whether
precise or otherwise). Second, it makes sense to talk about
values only when given a type under which to interpret a given
representation.

If you read through the sections where the term "value" is used,
thoroughly and carefully, I believe you'll see that the term is
used with different senses in different places, and also that the
meaning is context dependent -- often times with the context being
supplied only implicitly.

Perhaps you have too little confidence in the standard document's
authors' ability to express themselves.

In fact, I have great confidence in the authors' ability to express
themselves. In this case however I believe their ability was not
realized as fully as it might be. The language about "values" does
a reasonably good job (IMO) of expressing *accurately*; it doesn't
do so well (again, IMO) in expressing *clearly*.
 
D

Dietmar Schindler

Tim said:
The written wording should be authoritative, if there is agreement
about what the written wording says. Unfortunately that's not the
case in this discussion.

What you write below clarifies your view. It seems that we just can't
follow each other's lines of thought. I'll insert my judgement where it
differs from yours. If we don't get further evidence from a third party,
we probably have to agree to disagree.
As used in the C99 document, the term "value" is context dependent.
A particular set of bits can represent a value under one type and
not represent a value under another type. It's impossible to say
whether a given representation is a value or not, without first
knowing the context of what kind of value is being asked about.

3.17.2
1 indeterminate value
either an unspecified value or a trap representation

Since even a trap representation is a value (however indeterminate), I
can't see how any given representation can not be a value.
(The question also depends on implementation choices of which
representations correspond to values under each particular type.)

Also, the term "value" is used in different senses in the C99
document. The definition of value is stated (in 3.17 p1) as:

precise meaning of the contents of an object when
interpreted as having a particular type

Notice two things about this definition. First, it's impossible
to store a "value" in an object. Objects hold representations,
or if you prefer, bits; they do not hold "meanings" (whether
precise or otherwise). Second, it makes sense to talk about
values only when given a type under which to interpret a given
representation.

(How can I store something in an object without using a type?)
Your first point, as I see it, is contradicted at several places in the
standard, such as

""Modify includes the case where the new value being stored is the
same as the previous value."

"Such an object exists and retains its last-stored value during the
execution of the block ..."

"An object exists, has a constant address,25) and retains
its last-stored value throughout its lifetime."
If you read through the sections where the term "value" is used,
thoroughly and carefully, I believe you'll see that the term is
used with different senses in different places, and also that the
meaning is context dependent -- often times with the context being
supplied only implicitly.

I think I read through the sections thoroughly and carefully, but I'm
afraid I read them differently.
 
D

Dietmar Schindler

Tim said:
Dietmar Schindler said:
Tim said:
Look at 6.2.6, "Representations of Types". Pay special
attention to "trap representations". The description of
trap representations is so permissive that seems like
bitwise operators on negative operands can result in
undefined behavior at any time. Remember the rule - if
behavior isn't explicitly defined, it's undefined. However,
if that isn't enough, a case of undefined behavior is called
out explicitly in 6.2.6.2 p2,p4. The simple expression

-1|-2

may generate a bit pattern that corresponds to a "negative
zero" (on a ones-complement machine); if the implementation
doesn't support negative zeros, the behavior is undefined.

6.2.6.1 General

[#8] ... Where a
value is stored in an object using a type that has more than
one object representation for that value, it is unspecified
which representation is used, but a trap representation
shall not be generated.

In this case the bit pattern that is generated is not a
value, so 6.2.6.1 p8 doesn't apply.

I just discovered a bad mistake that I made. I had looked up 6.2.6.2,
paragraph 4 in the old draft WG14/N869, but this has become paragraph 6.
WG14/N1124 has this paragraph:

6.2.6.2 Integer types
4 If the implementation does not support negative zeros, the behavior of
the &, |, ^, ~, <<, and >> operators with arguments that would produce
such a value is undefined.

According to this, your assertion of the possibility of undefined
behavior is of course correct, although in my opinion not for the reason
"the bit pattern that is generated is not a value", but simply because
it is expressly stated in the above paragraph.

I apologize for my fault, but perhaps you enjoyed the discussion in the
other subthread, even if we didn't come to an agreement.
 
K

kuyper

Dietmar said:
Tim Rentsch wrote: ....

3.17.2
1 indeterminate value
either an unspecified value or a trap representation

Since even a trap representation is a value (however indeterminate), I
can't see how any given representation can not be a value.


6.2.5p5: "Certain object representations need not represent a value of
the object type. ... Such a representation is called a trap
representation."

Thus, if an indeterminate value is a trap representation, it does NOT
represent a value. The phrase "indeterminate value" is C jargon: you
can't conclude that it's a value just because it's name contains the
word "value". It's often a value, hence the name, but it's not always a
value. This isn't unusual: for instance, a "null pointer constant"
isn't necessarily a pointer, sometimes it's an integer constant
expression with a value of 0, and there's no meaningful sense within
the standard in which a "null pointer" actually points at anything.
When the standard provides an explicit definition for a phrase, that
definition is the only thing that applies within the context of the
standard - you can't analyse the meanings of the component words of the
phrase to get any additional information about the meaning.
(How can I store something in an object without using a type?)

You can't.
 

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,744
Messages
2,569,479
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top