473,394 Members | 1,750 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

compare a large number of variables

Hi,

I wonder if there is a nice bit twiddling hack to compare a large
number of variables?

If you first store them in an array, you can do:

for (i = 0; i < n; i++) {
if (array[i] != value) {
/* array[i] differs from value, do something*/
}
}

but I dont have the variables in an array, and would like to figure out
a nice oneliner.

best regards.
E.

Nov 15 '05
122 5174

In article <pa****************************@dodo.com.au>, Netocrat <ne******@dodo.com.au> writes:
mw*****@newsguy.com (Michael Wojcik) wrote:
Netocrat <ne******@dodo.com.au> writes:
The alternative would be a new operator for multi-way comparisons, such as
===, which would be used similarly to the (a?b:c) construct except that
the ? and : would both be replaced by === and it could be used for more
than three operands.
For === to work, the grammar has to expand the phrase to include all the
"===" operations in the chain, so all the operands can be evaluated,
then their values compared, then the result of all the chained ===
comparisons computed.

Nothing else in C works that way.


On its own - which admittedly I don't think is how you intended the
statement to be read - that's not reason enough to reject the proposal.


True. Let me rephrase: the C standard defines the language using a
formal grammar, which decomposes into simple expressions. In my
opinion, the semantics of the proposed operator prevents it from
fitting comfortably into this grammar, because it can't be reduced
to a series of applications of itself.

That is, you can't have a rule like:

multiway-equality-expression:
equality-expression
multiway-equality-expression === equality-expression

(see the grammar in Annex B of 9899-1990) because the chain of
multiway-equality-expressions has to be evaluated as a whole.

That's really my objection - I don't like what it does to the
grammar.
On the other hand I think that the advantage of a new operator is that it
would make it clearer to a compiler and reader what is intended and allow
for more concise code, which *is* in keeping with C's spirit.
I'll agree concision is a design goal for C (albeit in moderation -
there are more concise languages), though it's a concision of the
language itself, and not necessarily of programs written in it. C
generally avoids providing syntactic sugar, preferring to make most
things explicit; thus we have malloc rather than something like
new, and case fall-through rather than syntax for multiple cases,
and so forth.

I could be persuaded that multiway comparison is sufficiently
explicit to be C-like, though, if other problems were solved.
or how it interacts with operators like comma


Probably the comma operator would have higher precedence than the ===
operator. So, for example, the expression:
a === b, c === d, e === f

would mean:
a === (b, c) === (d, e) === f


I suspect that won't work well. There's a sequence point after
evaluating the LHS of the comma operator. I suspect that will
lead to some ugly confusion.
Probably these operators would have higher precedence.


They'd have to, if the comma operator has higher precedence.
Currently comma has the lowest precedence (in effect - see various
discussions about what "precedence" really means in C), so if
multiway comparison is lower than comma, it's lower than everything
else, too.

But again that means you've got sequence points in the middle of
evaluating your operator. That's not unusual in itself; for
example there are two sequence points in:

strlen(x) == strlen(y)

before the equality can be evaluated. However, my feeling is that
the "chaining" nature of === makes handling sequence points more
complicated.

Maybe what you really want is an operator that's like the comma
operator (including having a sequence point after the LHS is
evaluated), except that rather than discarding the result of the
LHS, it compares it with the RHS. I'd give this precedence right
above the comma operator. However, this still has the chaining
problem - the implementation has to treat the result of the
comparison differently depending on whether it is itself an
operand to the new operator.

Really, I think this is best handled as a variadic function:

#include <stdarg.h>
int AllEqual(int *Op, ...)
{
int Result;
int Value;
va_list Args;

if (!Op) return 1; /* all members of empty set are equal */

va_start(Args, Op);
Value = *Op;
for (Result = 1; Op && Result; Op && (Result = (*Op == Value)))
Op = va_arg(Args, int *);
va_end(Args);

return Result;
}

Then you have:

if (! AllEqual(&v, &a, &b, &c, (int *)0))
/* one or more of a, b, c is not equal to v */

It doesn't give you the automatic type conversions that you have with
==, but on the other hand it does enforce type safety, which may be
more valuable in a case like this - since if you're comparing a whole
series of variables to a single value, they're likely to all be of
the same type anyway.
So, if you just add some APL to C, you'd be able to do what you want.
:-)


Judging from the Wikipedia article, there's only one way that any APL
could be added to C...


Well, there are ASCII-only APL derivatives, notably J. J uses many
of the punctuation characters that C uses, but it would be possible
to bolt J onto C by delimiting the J expressions. Not that I'd
recommend it.

--
Michael Wojcik mi************@microfocus.com

Cooperation is just like two pagodas, one hardware and one software.
-- Wen Jiabao
Nov 15 '05 #51
On Thu, 25 Aug 2005 14:08:26 +0000, Michael Wojcik wrote:
Netocrat <ne******@dodo.com.au> writes:
mw*****@newsguy.com (Michael Wojcik) wrote:
> Netocrat <ne******@dodo.com.au> writes:
That is, you can't have a rule like:

multiway-equality-expression:
equality-expression
multiway-equality-expression === equality-expression

(see the grammar in Annex B of 9899-1990) because the chain of
multiway-equality-expressions has to be evaluated as a whole.
I only have access to the drafts, and Annex B does not occur in the
ANSI C89 draft and it's a library summary in the C99 draft. Did you mean
the Annex/Appendix titled "Language Syntax Summary"?

At any rate I'm not sure what your objection is. It seems to me that the
grammar is not intended to specify such things as order of evaluation -
surely that's up to the semantic and constraint rules.
That's really my objection - I don't like what it does to the grammar.
Perhaps you could explain what I'm missing - how is it any different to
any other compound expression that the grammar describes but whose
behaviour is more completely specified by other descriptive rules?

[...] I could be persuaded that multiway comparison is sufficiently explicit
to be C-like, though, if other problems were solved.
Keep pointing them out and let's see if any turn out to be intractable.
> or how it interacts with operators like comma


Probably the comma operator would have higher precedence than the ===
operator. So, for example, the expression: a === b, c === d, e === f

would mean:
a === (b, c) === (d, e) === f


I suspect that won't work well. There's a sequence point after
evaluating the LHS of the comma operator. I suspect that will lead to
some ugly confusion.


There's a precedent in the ?: construct as I've written elsewhere, in
that:
a ? b, c : d, e
means:
a ? (b, c) : (d, e)

A lot of things in C seem confusing until you understand how they are
defined; I believe that could apply to this situation. Point out any
specific undefinedness that you can see and I'll try to come up with
appropriate semantics.

[...] However, my feeling is that
the "chaining" nature of === makes handling sequence points more
complicated.
Perhaps that the order of evaluation could be specified as left-to-right,
shortcircuiting if a mismatch is found, which seems to be similar to what
you suggest below.
Maybe what you really want is an operator that's like the comma operator
(including having a sequence point after the LHS is evaluated), except
that rather than discarding the result of the LHS, it compares it with
the RHS. I'd give this precedence right above the comma operator.
However, this still has the chaining problem - the implementation has to
treat the result of the comparison differently depending on whether it
is itself an operand to the new operator.
You're presumably again referring to whether this could be expressed by
the Standard's grammatical rules. Again, I can't see where it's specified
in the standard that this is inconsistent with the current grammar - why
can an intermediary result not be part of the process of creating the
final result of the expression?
Really, I think this is best handled as a variadic function:

#include <stdarg.h>
int AllEqual(int *Op, ...)
{
int Result;
int Value;
va_list Args;

if (!Op) return 1; /* all members of empty set are equal */

va_start(Args, Op);
Value = *Op;
for (Result = 1; Op && Result; Op && (Result = (*Op == Value)))
Op = va_arg(Args, int *);
va_end(Args);

return Result;
}

Then you have:

if (! AllEqual(&v, &a, &b, &c, (int *)0))
/* one or more of a, b, c is not equal to v */

It doesn't give you the automatic type conversions that you have with
==, but on the other hand it does enforce type safety, which may be more
valuable in a case like this - since if you're comparing a whole series
of variables to a single value, they're likely to all be of the same
type anyway.


That depends on what you mean by type safety. Your function expects that
all of the arguments are pointers to int but there will be no compiler
warning if only one of them is instead e.g. a pointer to short (this
falsely returns unequal on little-endian implementations where short is
smaller than int) or pointer to long (this potentially does likewise on
big-endian implementations where long is larger than int). Agreed, they
will typically be the same type but the function's expectation of this
makes it unsafe. Perhaps it would be better named AllIntEqual.

So that's another approach to add to the bitwise comparisons. I'd still
like to see if there are any insoluble problems with a multi-way equality
operator.

[...]

--
http://members.dodo.com.au/~netocrat
Nov 15 '05 #52
"Mark" <so***@localbar.com> writes:
"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu...
"Mark" <so***@localbar.com> writes:
"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu...
> "Mark" <so***@localbar.com> writes:
>> "Netocrat" <ne******@dodo.com.au> wrote in message
>> news:pa****************************@dodo.com.au...
>> >[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; and also because I've been optimistic
enough to think that one or more of those might change
sometime soon.

This understanding is consistent
with the wording of the standard, "A computation involving
unsigned operands can never overflow," 6.2.5 p9.

Then I was correct in my initial statement that in my example
'Overflow is not possible.' - I was concerned after seeing H.2.2 that
my statement was incorrect, so I ammended it to 'not an issue'.
I now retract my ammended statement and stand by my original claim.
Thanks for the citation. :-)


The comment I think you're referring to is one you made in
an earlier post that isn't quoted above; namely:
if(a-b|b-c|c-d|d-e /* ... */)
puts("mismatched");
else
puts("pick one... they're all the same");
All zero? Overflow?


Overflow is not possible, stare at it for a while and
see if you can figure out why ;)


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.

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. 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).

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.

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?
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.

If what is
being talked about is overflow -- which I think is a reasonable
assumption considering the context -- then the relevant portion
of the cited H.2.2 is only that about signed integer types.

But we have been dealing with bit operands the entire time,
so considering the context you should assume we are
dealing with unsigned integer types, no? I have been... which again
is why I earlier stated that 'overflow is not possible'.


You may imagine that the operands were "bit operands", but
there is nothing in what you wrote to indicate that; and,
to the contrary in earlier postings when variables were
declared as 'int' rather than 'unsigned int'. Maybe you
think "bit operators" (such as '|') imply "bit operands"
(meaning unsigned), but of course they don't.

[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.

Section 3.4 defines different kinds of
behaviors, with 3.4.3 defining "undefined behavior". I don't
know what document you have.

Nor do I know what you are reading if it truly defines
a 'ceiling' function.


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.
Nov 15 '05 #53

In article <pa**************************@dodo.com.au>, Netocrat <ne******@dodo.com.au> writes:
On Thu, 25 Aug 2005 14:08:26 +0000, Michael Wojcik wrote:
Netocrat <ne******@dodo.com.au> writes:
mw*****@newsguy.com (Michael Wojcik) wrote:
> Netocrat <ne******@dodo.com.au> writes:
That is, you can't have a rule like:

multiway-equality-expression:
equality-expression
multiway-equality-expression === equality-expression

(see the grammar in Annex B of 9899-1990) because the chain of
multiway-equality-expressions has to be evaluated as a whole.


I only have access to the drafts, and Annex B does not occur in the
ANSI C89 draft and it's a library summary in the C99 draft.


Well, yes, it wouldn't be the same thing in C99, since that's a
different standard (9899-1999). I have the real 9899-1990, not
the final draft, so I'm not sure what's in the latter.
Did you mean the Annex/Appendix titled "Language Syntax Summary"?
That's the one.
At any rate I'm not sure what your objection is. It seems to me that the
grammar is not intended to specify such things as order of evaluation -
surely that's up to the semantic and constraint rules.
The grammar determines precedence - see any number of discussions
on that topic that have appeared here. And while Annex B itself is
informative, it merely duplicates normative material from the Syntax
sections in the main body of the standard. If you add a new
operator, the grammar has to be extended to accomodate it.
That's really my objection - I don't like what it does to the grammar.


Perhaps you could explain what I'm missing - how is it any different to
any other compound expression that the grammar describes but whose
behaviour is more completely specified by other descriptive rules?


I believe that if you try to add it to the grammar you'll see what
the problem is. I can't find any simple change to the grammar that
accomodates it and expresses the precedence that you want.

If you believe otherwise, show me what it'd be.
A lot of things in C seem confusing until you understand how they are
defined; I believe that could apply to this situation. Point out any
specific undefinedness that you can see and I'll try to come up with
appropriate semantics.
You're conflating confusion and undefinedness here; they're two
different sources of difficulty. And "seems confusing" is redundant;
confusion is subjective - it's always and only a matter of "seeming".
If a significant number of readers find a construct confusing, then
it is confusing.

I'm not particularly interested in identifying specific situations
where the mooted operator is problematic. I don't like it; I believe
its "chaining" behavior violates the underlying phrase grammar of C.
Unless you get the committee to consider including it, though, I
needn't worry about objecting in any more specific terms, since until
then it's entirely speculative.

But since you asked:

int a, b, c, d, e;
a = b = c = d = e = 2;
if (a === b === (c === d === e))
puts("a parenthesized === evaluates to the value of its operands");
else
puts("a parenthesized === evaluates to its logical value");

Which is the correct behavior, and why? What happens if you have a
multiway comparison in a macro and you substitute it into a
multiway-comparison expression, or if you use a multiway-comparison
expression as the argument to a macro? What will programmers expect?

#define BOTH_TRUE(x, y) (x)===(y)===1
if (BOTH_TRUE(a==b, c===d===e)) ...
However, my feeling is that
the "chaining" nature of === makes handling sequence points more
complicated.


Perhaps that the order of evaluation could be specified as left-to-right,
shortcircuiting if a mismatch is found, which seems to be similar to what
you suggest below.


No, I didn't suggest short-circuiting. I don't believe short-
circuiting solves anything here.
Maybe what you really want is an operator that's like the comma operator
(including having a sequence point after the LHS is evaluated), except
that rather than discarding the result of the LHS, it compares it with
the RHS. I'd give this precedence right above the comma operator.
However, this still has the chaining problem - the implementation has to
treat the result of the comparison differently depending on whether it
is itself an operand to the new operator.


You're presumably again referring to whether this could be expressed by
the Standard's grammatical rules. Again, I can't see where it's specified
in the standard that this is inconsistent with the current grammar - why
can an intermediary result not be part of the process of creating the
final result of the expression?


That's not the problem; the problem is that the "final result" depends
on whether the expression is itself the operand of your new operator.

Think of it from the parser's point of view. An equality-expression
(that isn't a relational-expression), for example, always evaluates
to either a 1 or a 0. The parser always generates the same code (or
intermediate representation) for the result of the equality-
expression. For your operator, though, the parser needs to look back
up the parse tree to see whether the result of a === comparison will
be a logical value (ie 0 or 1), or the value of the two operands (if
they're equal and the expression is itself the operand of another
===), or some other magic token (if they're inequal and the expression
is the operand of another ===).

Now, if you put a sequence point after evaluating the LHS of a ===,
and make it short-circuiting, that does simplify parsing: you can
just decompose into a series of nested if's and a temporary for
holding the value of the first operand. However, I think at that
point you've imposed so many restrictions on your operator that it's
will only rarely be useful. (Frankly, I don't see that it'd be all
that useful in the first place. I'd have to see some empirical
analysis of how often it'd likely be useful before I could advocate
it.)
Really, I think this is best handled as a variadic function:

...

It doesn't give you the automatic type conversions that you have with
==, but on the other hand it does enforce type safety...


That depends on what you mean by type safety.


Nothing. Ignore that bit. I don't know what I was thinking of
there; of course there's no type safety with a variadic function.
Perhaps it would be better named AllIntEqual.
Actually, in any real use, I expect it would have some much more
sensible name referring to its actual purpose. I still don't believe
it has much general utility.
So that's another approach to add to the bitwise comparisons. I'd still
like to see if there are any insoluble problems with a multi-way equality
operator.


There's a great gulf between "no insoluble problems" and "worth
having", of course.

In Scheme, you could easily create your operator using extend-syntax
(which is a pattern-matching recursive macro facility), by converting
it into a series of cascading if's. Maybe you should try it there
just to see whether it's really worth it. Scheme's a fun language.

--
Michael Wojcik mi************@microfocus.com

Therefore, it is possible to enjoy further by using under the
Netscape 2.0. However, Netscape will hangup at sometimes. You
should give it up. -- roro
Nov 15 '05 #54
On Fri, 26 Aug 2005 13:56:08 +0000, Michael Wojcik wrote:
[...]
The grammar determines precedence - see any number of discussions on
that topic that have appeared here.
I was under the misapprehension that the grammar notation itself
determined only syntax, not precedence.

[regarding a multi-way equality operator] I believe that if you try to add it to the grammar you'll see what the
problem is. I can't find any simple change to the grammar that
accomodates it and expresses the precedence that you want.
Neither can I, partly because I haven't examined closely how the notation
works and is complemented by other parts of the standard. If I come
across a solution I'll post it.

[...] int a, b, c, d, e;
a = b = c = d = e = 2;
if (a === b === (c === d === e))
puts("a parenthesized === evaluates to the value of its
operands");
else
puts("a parenthesized === evaluates to its logical value");

Which is the correct behavior, and why?
The second option could cause programmer errors due to macros as you later
pointed out, although aside from that I think its behaviour is more
consistent with the behaviour of parentheses in other situations than the
first option.

Similar problems already exist with macros in general for other situations
(e.g. calling a macro with a single expression for which side-effects
unintendedly are evaluated twice). The potential for unintended behaviour
seems to me to lie more with the nature of macros than the proposed
operator.

Errors could be avoided by using a guideline that one should never call a
macro directly with a multi-way comparison expression unless one was
guaranteed of specific macro behaviour.

[...] [T]he problem is that the "final result" depends on whether the
expression is itself the operand of your new operator.

Think of it from the parser's point of view. [...]

OK, it's harder for the parser. But given that most modern compilers are
written with optimisation features in mind, and that this construct may
facilitate optimisation, the extra complexity in the parser may be
worthwhile.
Now, if you put a sequence point after evaluating the LHS of a ===, and
make it short-circuiting, that does simplify parsing: you can just
decompose into a series of nested if's and a temporary for holding the
value of the first operand. However, I think at that point you've
imposed so many restrictions on your operator that it's will only rarely
be useful.
For complex expressions you are probably right. For simpler expressions,
the sequence points needn't affect the compiler's ability to optimise and
rewrite the code.
(Frankly, I don't see that it'd be all that useful in the first place.
I'd have to see some empirical analysis of how often it'd likely be
useful before I could advocate it.) [...] There's a great gulf between "no insoluble problems" and "worth having",
of course.


The only problem that I have no answer for is that it is a bad match for
the standard's grammar description.

As to its general utility, I agree that it isn't clear, although I know
that there have been times in the past when I would have used it had it
been available. Offhand I don't know how frequent they have been.

[...]
--
http://members.dodo.com.au/~netocrat
Nov 15 '05 #55
On Fri, 19 Aug 2005 18:06:39 GMT, CBFalconer <cb********@yahoo.com>
wrote:
<snip>
If the values are in an array A[N] then you can use:

for (unequal = 0, i = 1; i < N; i++) {
if (A[i] |= A[i-1]) {
<cough> != </>
unequal = 1;
break;
}
}
if (unequal) different();
else same();

and this will function for ints as well as unsigned.


- David.Thompson1 at worldnet.att.net
Nov 15 '05 #56
On Fri, 19 Aug 2005 21:51:03 GMT, "Mark" <so***@localbar.com> wrote:
"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu...
"Mark" <so***@localbar.com> writes:
"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu... > Indeed, what happens on integer overflow is cited as an
> example (3.4.3 p3) in the definition of undefined behavior.
3.18.3 - no?


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.
I assume you are referring to the 'ceil' functions?
7.12.9.1 in my text... I am using the last version of the committee draft
Section 3.4 defines different kinds of
behaviors, with 3.4.3 defining "undefined behavior". I don't
know what document you have.

Nor do I know what you are reading if it truly defines a 'ceiling' function.

This was changed between n869 and actual C99.

n869 has the definition of the term undefined behavior at 3.18. C99
has definitions of impl-def, locale-spec, undefined, and unspecified
behaviors grouped under 3.4, and 3.18 and 3.19 are definitions of the
usual math notation for ceiling and floor -- vertical lines with
inward serifs at top or bottom -- which are used for ceil() and
floor() in n869 7.12.9.1,2 without definition, presumably understood
as standard math, just like + for addition (still) isn't defined; and
used in the same section of C99 for what are now {ceil,floor}{,f,l}();
and also a few other places the same in both documents.

The actual definition of undefined behavior, including the
(nonnormative) note and example, is unchanged.

- David.Thompson1 at worldnet.att.net
Nov 15 '05 #57
Einar wrote:
Yes, your suggestions work perfectly, but I was mor looking for a nice
bit operator to operate on all my variables and then to compare it with
the value. something like (a|b|c|d...z) != value (this wont work
however... ). This is just to get rid of a for-loop or lots of
if-statements, so it is nothing necesary, I'm just convinced that it is
possible to solve in another way, and I can't forget about it....
Ahhhrg.


#define X(var) if ((var) == value) { /* do something */ }

X(a) X(b) X(c) ... etc.

---
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Nov 15 '05 #58
In article <pa**************************@dodo.com.au>
Netocrat <ne******@dodo.com.au> wrote:
There's a precedent in the ?: construct as I've written elsewhere, in
that:
a ? b, c : d, e
means:
a ? (b, c) : (d, e)


Actually, this is wrong:

a ? b, c : d, e

parses the same as:

(a ? b, c : d), e

so that the value of the entire expression is that of "e".

(No parentheses are required inside the ?: portion for the same
reason that no parentheses are required in subscript brackets: the
syntax offers no way to terminate the sub-expression other than
the "closing bracket".)

As for the original subject (of comparing expr0 against a sequence
of expressions expr1,expr2,...,exprN to see if they are all equal,
or perhaps if any are equal): someone else mentioned APL elsethread.
APL does have a nice way to do this, provided the N expressions
are contained in a vector.

If variable X contains a vector, the expression "rho X" (where rho
is a Greek rho character) produces, as a scalar, the number of
elements in the vector. (Applied to a matrix, rho X is a vector
giving the size of the matrix, and so on.)

Used as a dyadic (two-operand) operator with two scalars, A rho B
will produce A a vector containing A copies of the value B. Hence
if E contains the expression expr0 to be compared, (rho X) rho E
will produce a vector consisting of N copies of E, which can now
be compared to the vector X.

When applied to two vectors with the same number of elements, the
dyadic "=" operator produces as its result a vector of integers
whose values are 0 where the two elements differ, and 1 where the
two elements are the same. Hence:

X = (rho X) rho E

will produce, e.g.:

0 0 1 1 0 1

when X is 3 4 5 5 6 5 and E is 5.

Now all we have to do is reduce this vector of 0-or-1 values into
the final desired value. To do this, we use the "reduce" operator
"/", which inserts some other operator -- such as "+" or "*" --
between all the various elements of a vector. In effect, +/ 0 1
2 means 0 + 1 + 2 (which is of course 3). If we want to know
whether *all* elements of X are equal to E, we simply use the "*"
operator on all the values, so that any zeros multiply out to cause
the entire result to be zero; otherwise we use the "+" operator,
so that any nonzero inputs cause the sum to be nonzero.

Hence:

*/ X = (rho X) rho E

is an APL one-liner that tells you whether all the elements of X
are equal to E.

In C, of course, I would prefer to just write a little function:

int alleq(int e, int *x, size_t nx) {
size_t i;

for (i = 0; i < nx; i++)
if (e != x[i])
return 0;
return 1; /* note that alleq(any, ptr, 0) is always 1 */
}

This does, of course, require the values to compare to be in a
vector (as does the APL one-liner).
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 15 '05 #59
On Sun, 28 Aug 2005 22:34:25 +0000, Chris Torek wrote:
In article <pa**************************@dodo.com.au>
Netocrat <ne******@dodo.com.au> wrote:
There's a precedent in the ?: construct as I've written elsewhere, in
that:
a ? b, c : d, e
means:
a ? (b, c) : (d, e)
Actually, this is wrong:

a ? b, c : d, e

parses the same as:

(a ? b, c : d), e

so that the value of the entire expression is that of "e".


I appreciate you pointing that out and it clearly makes sense given the
precedence of the comma operator.
(No parentheses are required inside the ?: portion for the same
reason that no parentheses are required in subscript brackets: the
syntax offers no way to terminate the sub-expression other than
the "closing bracket".)
Granted, but my point in including them was to make the operands of the
first comma explicit because I wanted the same semantics for the multi-way
equality operator.
As for the original subject (of comparing expr0 against a sequence
of expressions expr1,expr2,...,exprN to see if they are all equal,
or perhaps if any are equal): someone else mentioned APL elsethread.
APL does have a nice way to do this, provided the N expressions
are contained in a vector. [...] */ X = (rho X) rho E

is an APL one-liner that tells you whether all the elements of X
are equal to E.
That's quite neat and concise. To do that in C we would need to add the
reduce operator to the syntax. rho X in C would be sizeof X / sizeof *X.
It's not so simple in C to extend E into a vector - although C99's
variable arrays help. We can declare:

type Evec[sizeof X / sizeof *X];

In comparison to APL we need to know the type of X. A typeof operator
would be useful there.

Then to set all the vector elements we might use a function or macro
(whose implementation should be obvious):

setvec(Evec, sizeof X / sizeof *X, E);

Finally the missing link is something that you partly canvassed in a
separate thread - operators that work on entire arrays. In this case we
need it to be the equality operator, however that already has different
semantics. If the array types were unsigned we could use an array
subtraction operator without overflow concerns, for a final "one-liner":

*/ (X - Evec)
In C, of course, I would prefer to just write a little function:

int alleq(int e, int *x, size_t nx) {
size_t i;

for (i = 0; i < nx; i++)
if (e != x[i])
return 0;
return 1; /* note that alleq(any, ptr, 0) is always 1 */
}
}
This does, of course, require the values to compare to be in a vector
(as does the APL one-liner).


If you have an array that's fine, but it isn't very flexible to require
an array. A variadic function would be flexible at the expense of type
safety. The multi-way equality operator I've proposed (===) would be
flexible and type-safe but not as concise as a variadic function and
difficult to fit into the current grammar.

Here's an alternative that is concise, flexible and type safe (but
probably an even worse fit for the grammar...). It's a multi-way
equality operator named after your alleq function (the ellipsis is not
intended to imply that this is a variadic function, rather that it takes
an arbitrary number of operands):

alleq(a, b, ...)

The sizeof operator provides a precedent for the parentheses, but there is
no precedent for the variable-sized operand list separated by commas.

--
http://members.dodo.com.au/~netocrat
Nov 15 '05 #60
Netocrat wrote:
a ? b, c : d, e

means:
a ? (b, c) : (d, e)

(or at least that's how gcc treats it, I haven't consulted the standard to
confirm)


No, it means

(a ? (b, c) : d), e

(and I strongly believe that gcc treats it so).
Nov 15 '05 #61

Dietmar Schindler wrote:
Netocrat wrote:
a ? b, c : d, e

means:
a ? (b, c) : (d, e)

(or at least that's how gcc treats it, I haven't consulted the standard to
confirm)


No, it means

(a ? (b, c) : d), e

(and I strongly believe that gcc treats it so).


Yes.

#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>

Making a non zero hides this fact nicely, though!

Nov 15 '05 #62
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" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu...
"Mark" <so***@localbar.com> writes:
"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu...
> "Mark" <so***@localbar.com> writes:
>> "Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
>> news:kf*************@alumnus.caltech.edu...
>> > "Mark" <so***@localbar.com> writes:
>> >> "Netocrat" <ne******@dodo.com.au> wrote in message
>> >> news:pa****************************@dodo.com.au...
>> >> >[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.
> This understanding is consistent
> with the wording of the standard, "A computation involving
> unsigned operands can never overflow," 6.2.5 p9.

Then I was correct in my initial statement that in my example
'Overflow is not possible.' - I was concerned after seeing H.2.2 that
my statement was incorrect, so I ammended it to 'not an issue'.
I now retract my ammended statement and stand by my original claim.
Thanks for the citation. :-)


The comment I think you're referring to is one you made in
an earlier post that isn't quoted above; namely:
> >> if(a-b|b-c|c-d|d-e /* ... */)
> >> puts("mismatched");
> >> else
> >> puts("pick one... they're all the same");

>
> > All zero? Overflow?

>
> Overflow is not possible, stare at it for a while and
> see if you can figure out why ;)


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.
> If what is
> being talked about is overflow -- which I think is a reasonable
> assumption considering the context -- then the relevant portion
> of the cited H.2.2 is only that about signed integer types.

But we have been dealing with bit operands the entire time,
so considering the context you should assume we are
dealing with unsigned integer types, no? I have been... which again
is why I earlier stated that 'overflow is not possible'.


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.</q>
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 :)
> Section 3.4 defines different kinds of
> behaviors, with 3.4.3 defining "undefined behavior". I don't
> know what document you have.

Nor do I know what you are reading if it truly defines
a 'ceiling' function.


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
Nov 15 '05 #63
"Mark B" <so***@localbar.com> wrote in message
news:Pq*******************@monger.newsread.com...
<extremely large snip - just wanted to make one correction>
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 :-)

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

Nov 15 '05 #64
"Mark B" <so***@localbar.com> writes:
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...

"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu...
"Mark" <so***@localbar.com> writes:
"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu...
> "Mark" <so***@localbar.com> writes:
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.

The comment I think you're referring to is one you made in
an earlier post that isn't quoted above; namely:
> >> if(a-b|b-c|c-d|d-e /* ... */)
> >> puts("mismatched");
> >> else
> >> puts("pick one... they're all the same");
>
> > All zero? Overflow?
>
> Overflow is not possible, stare at it for a while and
> see if you can figure out why ;)


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?


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.

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.


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.

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?


See above.

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.


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.

> If what is
> being talked about is overflow -- which I think is a reasonable
> assumption considering the context -- then the relevant portion
> of the cited H.2.2 is only that about signed integer types.
But we have been dealing with bit operands the entire time,
so considering the context you should assume we are
dealing with unsigned integer types, no? I have been... which again
is why I earlier stated that 'overflow is not possible'.


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.</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.

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.


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.

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?


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.
Nov 15 '05 #65
"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu...
"Mark B" <so***@localbar.com> writes:

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
Nov 15 '05 #66
Suman wrote:
#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.
Nov 15 '05 #67
"Mark B" <so***@localbar.com> writes:
"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu...
"Mark B" <so***@localbar.com> writes:

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.


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.
Nov 15 '05 #68
"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu...
"Mark B" <so***@localbar.com> writes:
"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu...
> "Mark B" <so***@localbar.com> writes:
>
> I'm going to try to trim this down to just the relevant
> portions...
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
Nov 15 '05 #69
"Mark B" <so***@localbar.com> writes:
"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu...
"Mark B" <so***@localbar.com> writes:
"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu...
> "Mark B" <so***@localbar.com> writes:
>
> I'm going to try to trim this down to just the relevant
> portions...
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.

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.


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.

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 :(


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.
Nov 15 '05 #70
Mark B wrote:

"Tim Rentsch" <tx*@alumnus.caltech.edu> wrote in message
news:kf*************@alumnus.caltech.edu...
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 :(


Annex F applies to IEC 60559 floating-point arithmetic.
--
Dietmar
Nov 15 '05 #71
Tim Rentsch wrote:
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.
Nov 15 '05 #72
Dietmar Schindler <dS***@arcor.de> writes:
Tim Rentsch wrote:
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.
Nov 15 '05 #73
Tim Rentsch wrote:

Dietmar Schindler <dS***@arcor.de> writes:
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.

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.
Nov 15 '05 #74
Dietmar Schindler <dS***@arcor.de> writes:
Tim Rentsch wrote:

Dietmar Schindler <dS***@arcor.de> writes:
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.
Nov 15 '05 #75
Tim Rentsch wrote:

Dietmar Schindler <dS***@arcor.de> writes:

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.

Nov 15 '05 #76
Dietmar Schindler <sc**@arw0120.mra.man.de> writes:
Tim Rentsch wrote:

Dietmar Schindler <dS***@arcor.de> writes:

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.
Nov 15 '05 #77
Tim Rentsch wrote:

Dietmar Schindler <sc**@arw0120.mra.man.de> writes:
Tim Rentsch wrote:

Dietmar Schindler <dS***@arcor.de> writes:
>
> 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.
If you want to pursue the topic further, comp.std.c may
be a better place to do that.

Nov 15 '05 #78
Dietmar Schindler <dS***@arcor.de> writes:
Tim Rentsch wrote:
[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*.
Nov 15 '05 #79
Tim Rentsch wrote:
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.
Nov 15 '05 #80
Dietmar Schindler wrote:
Tim Rentsch wrote: ....
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.

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.

Nov 15 '05 #81
Tim Rentsch wrote:

Dietmar Schindler <dS***@arcor.de> writes:
Tim Rentsch wrote:
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.
Nov 15 '05 #82
Dietmar Schindler wrote:
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.


What is written always requires comprehension by the reader,
and sometimes that is lacking, whether from linguistic
difficulties, lack of clarity of the expression, or failure
to apply context from other parts of the document.

It is certainly the case that most integer types can have
trap representations, and that such representations are not
supposed to express "values", at least for most purposes.

The example -1|-2 using ones-complement representation is
specified as producing "minus zero", which may be a trap
representation. Such possibilities suggest that it is
wisest to use unsigned types for bitwise operations.
Nov 15 '05 #83
Dietmar Schindler <dS***@arcor.de> writes:
[...]
(How can I store something in an object without using a type?)


memcpy()

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #84
ku****@wizard.net writes:
Dietmar Schindler wrote:
Tim Rentsch wrote:

...
> 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.

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.


If you look at the English grammar of these terms, in the phrase "null
pointer constant" the phrase "null pointer" modifies the noun
"constant". The implication is that a "null pointer constant" is a
constant, not that it's a null pointer. (In fact it can't be a null
pointer; a null pointer constant exists only in the program source,
and a null pointer exists only during execution.)

Similarly, the grammar of the phrase "indeterminate value" implies
that it's a value -- and ideally all terms defined in C should obey
the rules of English grammar. If they don't, confusion is inevitable.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #85
On Wed, 07 Sep 2005 15:36:24 +0000, Keith Thompson wrote:
Dietmar Schindler <dS***@arcor.de> writes:
[...]
(How can I store something in an object without using a type?)


memcpy()


Or accessing its individual bytes with a char pointer.

--
http://members.dodo.com.au/~netocrat
Nov 15 '05 #86
In article <pa****************************@dodo.com.au>,
Netocrat <ne******@dodo.com.au> wrote:


On Wed, 07 Sep 2005 15:36:24 +0000, Keith Thompson wrote:
Dietmar Schindler <dS***@arcor.de> writes:
[...]
(How can I store something in an object without using a type?)


memcpy()


Or accessing its individual bytes with a char pointer.


A char pointer is a type.
Nov 15 '05 #87
an******@example.com (Anonymous 7843) writes:
In article <pa****************************@dodo.com.au>,
Netocrat <ne******@dodo.com.au> wrote:


On Wed, 07 Sep 2005 15:36:24 +0000, Keith Thompson wrote:
> Dietmar Schindler <dS***@arcor.de> writes:
> [...]
>> (How can I store something in an object without using a type?)
>
> memcpy()


Or accessing its individual bytes with a char pointer.


A char pointer is a type.


More to the point, char is a type.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #88
On Thu, 08 Sep 2005 01:29:31 +0000, Keith Thompson wrote:
an******@example.com (Anonymous 7843) writes:
In article <pa****************************@dodo.com.au>,
Netocrat <ne******@dodo.com.au> wrote:
On Wed, 07 Sep 2005 15:36:24 +0000, Keith Thompson wrote:
> Dietmar Schindler <dS***@arcor.de> writes:
> [...]
>> (How can I store something in an object without using a type?)
>
> memcpy()

Or accessing its individual bytes with a char pointer.
A char pointer is a type.


More to the point, char is a type.


You are both literally correct; but it seemed to answer Dietmar
Schindler's question in the context of the snipped material which prompted
him to ask it: Second, it makes sense to talk about
values only when given a type under which to interpret a given
representation.


In this sense the char type is better considered as representing only a
part of the object rather than being a representation of the object
itself, so I think my comment was valid.

--
http://members.dodo.com.au/~netocrat
Nov 15 '05 #89
Dietmar Schindler <dS***@arcor.de> writes:
Tim Rentsch wrote:

Dietmar Schindler <dS***@arcor.de> writes:
Tim Rentsch wrote:
> 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,


Glad to see the source of this part of the confusion was
discovered.

Note that my position is that undefined behavior is possible
even when two's complement representation is used. Two's
complement doesn't have a representation for negative zero,
so it isn't covered by the paragraph cited above. Even so,
bitwise operators on signed types that are represented using
two's complement may still result in undefined behavior.

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.
You say more about values in your other posting; I'll pick
up the discussion about values in a followup to that.

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


I would say that we neither did, nor did not, come to an
agreement. Rather, we didn't achieve understanding. Until
there is understanding the question of agreement can't
really be answered: how can someone know whether they agree
or disagree if they don't know what it is that they are
agreeing or disagreeing with?
Nov 15 '05 #90
Keith Thompson <ks***@mib.org> writes:
[snip]
If you look at the English grammar of these terms, in the phrase "null
pointer constant" the phrase "null pointer" modifies the noun
"constant". [snip]


<OTish>

That isn't the rule I learned.

When a noun is used in an adjective position, as "pointer" is in
this case, associate to the right: "easy programming manuals"
means programming manuals that are easy, not manuals about easy
programming. Similarly, the phrase "null pointer constant"
should be read as "null (pointer constant)".

To get the other reading, hyphenate: "(null pointer) constant"
should be written "null-pointer constant".

I'm not saying Keith's statement is wrong, only that it doesn't
agree with the usage rule that I was taught.

</OTish>
Nov 15 '05 #91
ku****@wizard.net wrote:
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.


Logic error: "not being a value of the object type" does not imply "not
being a value".
Nov 15 '05 #92
Douglas A. Gwyn wrote:

Dietmar Schindler wrote:
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.
What is written always requires comprehension by the reader,
and sometimes that is lacking, whether from linguistic
difficulties, lack of clarity of the expression, or failure
to apply context from other parts of the document.


That sounds reasonable.
It is certainly the case that most integer types can have
trap representations, and that such representations are not
supposed to express "values", at least for most purposes.


Some people (at least the two that I know of) are not so certain about
the latter.
Nov 15 '05 #93
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes:
[snip]
If you look at the English grammar of these terms, in the phrase "null
pointer constant" the phrase "null pointer" modifies the noun
"constant". [snip]


<OTish>

That isn't the rule I learned.

When a noun is used in an adjective position, as "pointer" is in
this case, associate to the right: "easy programming manuals"
means programming manuals that are easy, not manuals about easy
programming. Similarly, the phrase "null pointer constant"
should be read as "null (pointer constant)".

To get the other reading, hyphenate: "(null pointer) constant"
should be written "null-pointer constant".

I'm not saying Keith's statement is wrong, only that it doesn't
agree with the usage rule that I was taught.

</OTish>


Ok, I see your point. My parsing of the phrase "null pointer
constant" was influenced by knowing what the term actually means.

But "easy programming manuals", whether they're programming manuals
that are easy or manuals about easy programming, are manuals. They
aren't programming.

A null pointer constant, whether it's a pointer constant that's null
or a constant for a null pointer, is a constant; it's not a pointer.

(In fact, the interpretation that it's a constant for a null pointer
is most consistent with the actual meaning, even if it doesn't
necessarily follow from the English grammar.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #94
Dietmar Schindler <dS***@arcor.de> writes:
Tim Rentsch wrote:
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.


First we need to understand what the other person is saying.
I certainly wouldn't want to agree to disagree without first
knowing whether we're in agreement or in disagreement. :)

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.


Defined terms like this one are meant to be read as a single
indivisible unit. For example, 3.7.1 p1 defines "character"
as "single-byte character" or "<C> bit representation that
fits in a byte". In 3.7.2 p1, "multibyte character" is
defined as "sequence of one or more bytes representing a
member of the extended character set of either the source or
the execution environment." A "multibyte character" needn't
be a "character" in the sense of 3.7.1 p1. Nor in the sense
of 3.7: multibyte characters represent abstract characters,
but they are not actual characters - they are sequences of
bytes. Also, note that a multibyte character may be only
one byte long, so it need not be "multibyte".

And so: Saying X is an "indeterminate value" doesn't mean
that X is a value.

Whether a particular setting of bits corresponds to a trap
representation depends on what type is used to interpret the
bits in question. An eight-bit byte with all bits equal to
one could be a trap representation when accessed as a (one's
complement) signed char; but it wouldn't be (and couldn't
be) a trap representation when accessed as an unsigned char.
Saying an object holds a trap representation is meaningful
only when the object's contents are interpreted as some
particular type. If, being accessed using some type T1, an
object's contents correspond to a trap representation, then
they don't correspond to a value; if, being accessed using
some other type T2, those same contents correspond to a
value, then they don't correspond to a trap representation.

The previous paragraph uses "value" in the sense of 3.17 p1.

(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.


[see note 1]
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."


My statements were made about the definition in 3.17 p1, not
about other uses of the term "value". If there are uses of the
term "value" that are inconsistent with what the definition
implies, then those uses must be using the term "value" in a
different sense than 3.17 p1.

The statements you give support my assertion that the term
"value" is used with different senses in different places in
the Standard. What do you think "value" means in the
statements you quote, since it can't mean the same thing as the
definition in 3.17 p1?

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.


How *do* you read them? Not what conclusions do you draw, but
how do you read them? Can you articulate what (you think)
they say? Can you articulate what (you think) I think they
say?


[1] > (How can I store something in an object without using a type?)

Can't in C. Even functions like memcpy() act on "arrays
of character type and other objects treated as arrays of
character type" (7.21.1 p1).
Nov 15 '05 #95
Tim Rentsch wrote:

Dietmar Schindler <dS***@arcor.de> writes:
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.
First we need to understand what the other person is saying.
I certainly wouldn't want to agree to disagree without first
knowing whether we're in agreement or in disagreement. :)


That sounds reasonable.
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.


Defined terms like this one are meant to be read as a single
indivisible unit. For example, 3.7.1 p1 defines "character"
as "single-byte character" or "<C> bit representation that
fits in a byte". In 3.7.2 p1, "multibyte character" is
defined as "sequence of one or more bytes representing a
member of the extended character set of either the source or
the execution environment." A "multibyte character" needn't
be a "character" in the sense of 3.7.1 p1. Nor in the sense
of 3.7: multibyte characters represent abstract characters,
but they are not actual characters - they are sequences of
bytes. Also, note that a multibyte character may be only
one byte long, so it need not be "multibyte".


Your example seemed convincing to me at first, but unfortunately it
turned out not to be. You say "multibyte characters represent abstract
characters". I see that as compelling evidence that

3.7
1 character
<abstract> member of a set of elements used for the organization,
control, or representation of data

very well is the definition that applies to the sense in which it is
used in the term "multibyte character". So, a "multibyte character" is a
character (in the sense of 3.7).
And so: Saying X is an "indeterminate value" doesn't mean
that X is a value.
This is the very point which is contrary to my understanding of language
and logic - I'm afraid I just can't believe it.
My statements were made about the definition in 3.17 p1, not
about other uses of the term "value". If there are uses of the
term "value" that are inconsistent with what the definition
implies, then those uses must be using the term "value" in a
different sense than 3.17 p1.
What you say here is consistent, but
(a) 3.17 is the only place where the single term "value" is defined, and
(b) I can see no reason to assume that there are indeed uses of the term
"value" that are inconsistent with what the definition implies.
The statements you give support my assertion that the term
"value" is used with different senses in different places in
the Standard. What do you think "value" means in the
statements you quote, since it can't mean the same thing as the
definition in 3.17 p1?


In my opinion, in these statements

""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."

the meaning of "value" is not at all different from its definition in
3.17. When I insert the definition into the statements, I get

""Modify" includes the case where the new precise meaning of the
contents of the object when interpreted as having its specific type
being stored is the same as the previous precise meaning of the
contents of the object when interpreted as having its specific type."

"Such an object exists and retains its last-stored precise meaning of
the contents of the object when interpreted as having its specific
type during the execution of the block ..."

"An object exists, has a constant address,25) and retains its
last-stored precise meaning of the contents of the object when
interpreted as having its specific type throughout its lifetime."

This may sound a little clumsy, but it is not illogical, is it?
I think I read through the sections thoroughly and carefully, but I'm
afraid I read them differently.


How *do* you read them? Not what conclusions do you draw, but
how do you read them? Can you articulate what (you think)
they say? Can you articulate what (you think) I think they
say?


Above I made an attempt to do that.
Nov 15 '05 #96

Dietmar Schindler wrote:
ku****@wizard.net wrote:
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.


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


True, a trap representation, if interpreted using a type different from
it's actual object type, may represent a value. There's relatively few
cases where it's legal to access a object using a different type. If
it's a compatible type, the trap repsentation of the object will also
necessarily be a trap representation of the compatible type.

However, any object can be accessed as if it were an array of unsigned
char whose length is sizeof(object). When you access the repseentation
one byte at a time using an lvalue of unsigned char type, you aren't
retrieving a trap repesentation, since unsigned char is not allowed to
have any.

Nov 15 '05 #97
Dietmar Schindler <dS***@arcor.de> writes:
Tim Rentsch wrote:

Dietmar Schindler <dS***@arcor.de> writes: [snip]
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.


Defined terms like this one are meant to be read as a single
indivisible unit. For example, 3.7.1 p1 defines "character"
as "single-byte character" or "<C> bit representation that
fits in a byte". In 3.7.2 p1, "multibyte character" is
defined as "sequence of one or more bytes representing a
member of the extended character set of either the source or
the execution environment." A "multibyte character" needn't
be a "character" in the sense of 3.7.1 p1. Nor in the sense
of 3.7: multibyte characters represent abstract characters,
but they are not actual characters - they are sequences of
bytes. Also, note that a multibyte character may be only
one byte long, so it need not be "multibyte".


Your example seemed convincing to me at first, but unfortunately it
turned out not to be. You say "multibyte characters represent abstract
characters". I see that as compelling evidence that

3.7
1 character
<abstract> member of a set of elements used for the organization,
control, or representation of data

very well is the definition that applies to the sense in which it is
used in the term "multibyte character". So, a "multibyte character" is a
character (in the sense of 3.7).


Let's explore that. Characters are things like a, b, c, .... A
multibyte character is a sequence of bytes, ie a sequence of
memory locations. The set of characters is of some fixed size;
there are only so many of them. The set of (sequences of) memory
locations is of potentially unbounded size; certainly there can
be more memory locations than there are characters. If the set
of characters is smaller than the set of memory locations, how
can the set of memory locations be a subset of the set of
characters? If the set of memory locations is not a subset of
the set of characters, how can a memory location be a character?
A sequence of memory locations can represent characters, but they
are not themselves characters.

Similarly, the bit patterns in an eight-bit byte can represent
the numbers from zero to 255. We don't mean that a memory
location IS a number; a memory location -- or lots of different
memory locations -- can REPRESENT a number by having a certain
bit pattern stored in it (or them). There are only 256 numbers
between 0 and 255, but there are a lot more than 256 memory
locations -- there aren't enough numbers to go around so that
every memory location is a number. Or do you mean to say two
distinct memory locations can be the same, because they are
both (for example) the number 5?.

I think you're using "is" in the sense of "can stand in for".
And in that sense, I think I would agree with you -- a sequence
of memory locations (and the bit patterns stored therein) can
stand in for a character. But in technical writing the word "is"
is normally used in a different sense: if an X is a Y, then
the set of X's is a subset of the set of Y's. That sense of "is"
doesn't fit with what your statement about multibyte characters
implies.

And so: Saying X is an "indeterminate value" doesn't mean
that X is a value.


This is the very point which is contrary to my understanding of language
and logic - I'm afraid I just can't believe it.


Yes, I suspect the thread has lasted as long as it has because
your understanding of language and logic differs from that of
some other readers (mine in particular, but also some others).

My statements were made about the definition in 3.17 p1, not
about other uses of the term "value". If there are uses of the
term "value" that are inconsistent with what the definition
implies, then those uses must be using the term "value" in a
different sense than 3.17 p1.


What you say here is consistent, but
(a) 3.17 is the only place where the single term "value" is defined, and
(b) I can see no reason to assume that there are indeed uses of the term
"value" that are inconsistent with what the definition implies.


Here's an example. We store the bit pattern 1000000, with a
value of 0 (on a signed magnitude implementation), into an
eight-bit byte. Subsequent reads of the object alternately
return 00000000, 10000000, 00000000, ..., all of which still have
the value 0. Is this behavior allowed by the statement that "an
object retains its last-stored value"?

Second example:

int n;
unsigned char *p = (void*) &n;
p[0] = 0, p[1] = 1, p[2] = 2, p[3] = 3;

What is the last-stored value (in the sense of 3.17) of the
object n? Suppose the value (in the sense of 3.17) of n is
0x00010203; how could this value have been stored, since
no expression in the running program yields that value?

The statements you give support my assertion that the term
"value" is used with different senses in different places in
the Standard. What do you think "value" means in the
statements you quote, since it can't mean the same thing as the
definition in 3.17 p1?


In my opinion, in these statements [snipped to one representative]

"An object exists, has a constant address,25) and retains its
last-stored value throughout its lifetime."

the meaning of "value" is not at all different from its definition in
3.17. When I insert the definition into the statements, I get
[snipped to one representative]

"An object exists, has a constant address,25) and retains its
last-stored precise meaning of the contents of the object when
interpreted as having its specific type throughout its lifetime."

This may sound a little clumsy, but it is not illogical, is it?


Part of my problem with your reformulation is that I don't know
what the revised wording is meant to say. What is it that's
being stored? Is it a meaning, or a bit pattern? Let's look at
a slightly different wording:

"An object exists, has a constant address,25) and retains the
precise meaning of its last-stored contents of the object when
interpreted as having its specific type throughout its lifetime."

Does your statement mean the same thing as the rewording, or does
it mean something different? The rewording makes it clear that
what is being stored is "contents" rather than "meaning". A
"value" under 3.17 is a "meaning", so a 3.17-value is not what's
being stored (if the rewording is accurate). So which is it? Is
the statement about retaining the last-stored value inconsistent
with the 3.17 notion of value, or do you mean something different
by your statement than my proposed rewording? If the latter, then
what rewording would you propose?

I wouldn't say I find your revised definitions illogical,
but they do seem (at least to me) nonsensical.

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


How *do* you read them? Not what conclusions do you draw, but
how do you read them? Can you articulate what (you think)
they say? Can you articulate what (you think) I think they
say?


Above I made an attempt to do that.


Yes, and I give you credit for that. I've tried to divine what
it is you've been trying to say, and some of that is expressed
above (how I think you mean "is", for example). So let's see if
I can articulate what I think is the Standard is trying to say.
Disclaimer: very off-the-cuff remarks follow.

The word "value" is used in several senses in the Standard.
The definition given in 3.17 uses "value" in the sense of
how we are to interpret the contents of an object, when
interpreted in a particular context (namely, as what type).

Many places in the Standard use "value" not in the sense of 3.17,
but the sense of "raw bit pattern". Thus, when we say that an
object retains its last-stored "value", this wording is meant
to say that an object retains the last bit pattern stored into
that object. Similarly, we say a write access modifies an
object even if the raw bit pattern being stored matches the
bit pattern already in the object.

There is some confusion between the two senses, and that
confusion has prompted some esoteric discussion in the comp.*.c
newsgroups. For example, suppose a particular address is stored
in a pointer variable, and then the memory at that address is
deallocated (by calling free(), for example). Is the bit pattern
that was stored in the pointer allowed to change? I remember
there being discussion at some point on this question, although I
don't remember the outcome. However, part of what prompted the
discussion in the first place -- and what made it difficult -- is
the confusion over which sense of "value" is meant in statements
like "an object retains its last-stored value". If "value" means
"raw bit pattern" you reach one conclusion, and if "value" means
value-ala'-3.17 you (can) reach another. Some of the debate
centered around this confusion, although I don't remember if it
was ever explicitly identified.

Note that I'm not saying that one sense is the true sense and the
other sense is wrong; there is some ambiguity in the Standard
itself, and that ambiguity deserves (IMO) a DR (which hopefully
would result in revised and improved wording, but let's not get
into that right now). But -- and here is the important thing --
many places in the Standard where "value" is used are best read
as though "value" meant "raw bit pattern". And that sense of
value is definitely different than "value" as defined in 3.17.

Does that all make sense?
Nov 15 '05 #98
[groups revised back to just comp.lang.c]

Keith Thompson <ks***@mib.org> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes:
[snip]
If you look at the English grammar of these terms, in the phrase "null
pointer constant" the phrase "null pointer" modifies the noun
"constant". [snip]
<OTish>

That isn't the rule I learned.

When a noun is used in an adjective position, as "pointer" is in
this case, associate to the right: "easy programming manuals"
means programming manuals that are easy, not manuals about easy
programming. Similarly, the phrase "null pointer constant"
should be read as "null (pointer constant)".

To get the other reading, hyphenate: "(null pointer) constant"
should be written "null-pointer constant".

I'm not saying Keith's statement is wrong, only that it doesn't
agree with the usage rule that I was taught.

</OTish>


Ok, I see your point. My parsing of the phrase "null pointer
constant" was influenced by knowing what the term actually means.

But "easy programming manuals", whether they're programming manuals
that are easy or manuals about easy programming, are manuals. They
aren't programming.


Right. And certainly a null pointer constant is a constant and
not a pointer, no matter which grouping is used. Oh wait, you're
just about to say that...

A null pointer constant, whether it's a pointer constant that's null
or a constant for a null pointer, is a constant; it's not a pointer.

(In fact, the interpretation that it's a constant for a null pointer
is most consistent with the actual meaning, even if it doesn't
necessarily follow from the English grammar.)


I can see that point of view; there is such a thing as a null
pointer, and a (null pointer) constant is a constant that turns
into a null pointer.

I tend (slightly) to read it as null (pointer constant), because
there are other pointer constants:

static char buffer[100];
static char *buffer_p = &buffer[0];

It seems nice to say that what a static pointer variable can
initialized to is a pointer constant, and a pointer constant can
be either a null (pointer constant) or a non-null (pointer
constant), like the '&buffer[0]' initializer above. [I don't
know if the Standard ever uses the term "pointer constant"
(without "null" that is); the index doesn't have an entry for
it. I mean the term as one I happen to use, not an official
one.]

Again, I'm not saying my reading is better or righter than your
reading. It's just the reading that seems, to me, slightly more
satisfying.
Nov 15 '05 #99
Tim Rentsch wrote:

Dietmar Schindler <dS***@arcor.de> writes:
Tim Rentsch wrote:

Dietmar Schindler <dS***@arcor.de> writes:

> Tim Rentsch wrote:
> > 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.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,


Glad to see the source of this part of the confusion was
discovered.

Note that my position is that undefined behavior is possible
even when two's complement representation is used. Two's
complement doesn't have a representation for negative zero,
so it isn't covered by the paragraph cited above. Even so,
bitwise operators on signed types that are represented using
two's complement may still result in undefined behavior.


Yes, however your wording "seems like bitwise operators on negative
operands can result in undefined behavior at any time" seems somewhat
exaggerated to me. With two's complement representation, I find exactly
one possibility for undefined behavior, and that's in

6.2.6.2 Integer types
2 ...
Which of these applies is implementation-defined, as is whether the
value with sign bit 1 and all value bits zero ... is a trap
representation or a normal value.

The exclusion of other possibilities of undefined behavior of bitwise
operators when two's complement representation is used is suggested, as I
understand it, by footnotes 44 and 45, which say "no arithmetic operation
on valid values can generate a trap representation other than as part of
an exceptional condition such as an overflow."

Nov 15 '05 #100

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Mike | last post by:
My users have to select an value from a fixed selection of values. The obvious choice of control for such a requirement is to use a <select> (i.e. a combo box). My problem is that sometimes,...
3
by: Will McGugan | last post by:
Hi, Is there a simple way of replacing a large number of substrings in a string? I was hoping that str.replace could take a dictionary and use it to replace the occurrences of the keys with the...
5
by: David | last post by:
Hi all: I am processing a 3D bitmaps(essentially ~1024 2D bitmaps with a size of 1MB each). If I want read large amount of radom data from this series, how could I buffer the file to get...
3
by: vanvee | last post by:
Hi I have an application for my company's HR department where we store resumes for candidates we receive. I have an application that uses VB.Net and ADO.Net and data bindings (through code) to...
6
by: Alex | last post by:
Hi... I have a stored procedure that takes in a large number of parameters (around 30) and returns (as output parameters) another 10 or so. At the moment, each parameter is declared, defined...
2
by: =?Utf-8?B?UHJpeWE=?= | last post by:
Hi, I'm faced with a classic problem of how to update a large number of records from a web page. I;m trying to build an interface that will display recordset in the order of 3000 rows and allow...
8
by: theCancerus | last post by:
Hi All, I am not sure if this is the right place to ask this question but i am very sure you may have faced this problem, i have already found some post related to this but not the answer i am...
0
by: zephyrus360 | last post by:
This is about a technique to find the mod of a very large integer with a normal small integer. I recently encountered this problem when I needed to compute the modulus of a very large number with...
12
by: fermineutron | last post by:
I am trying to write a function which will convert a large ascii number, say 100 ascii digits, to its binary representation. It seems that evey algorithm I am trying to think of is backwards. ...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.