T.R | Title | User | Personal Name | Date | Lines |
---|
1298.1 | | WIBBIN::NOYCE | Pulling weeds, pickin' stones | Fri May 30 1997 12:23 | 17 |
| > ((ILE3_PQ)itmlst)++;
This is essentially the same as
((ILE_PQ)itmlst) = ((ILE_PQ)itmlst) + 1;
You can only apply "++" to an "lvalue" -- that is, a piece of
storage. You can't say "3++" or "(a+b)++", because "3" and
"a+b" aren't lvalue's. Neither is the result of a cast.
You could perhaps rewrite this as
(*((ILE3_PQ *) &itmlst)) ++;
That is, take the address of itmlst (and it had better be something
that you can take the address of!), pretend it's the address of an
ILE3_PQ thingy, and increment the ILE3_PQ that address points to.
You need to do the same with the ILEB_64_PQ version.
|
1298.2 | Coding style trivia | CXXC::REPETE | Rich Peterson 381-1802 ZKO2-3/N30 | Fri May 30 1997 15:14 | 56 |
| This function-like macro is written in a stylized way with enclosing
braces that allow its body to be modified but still have it safely
appear as a single statement wherever it might be invoked, which is
certainly good practice. But one nit that is sometimes picked on this
practice is that because the macro invocation looks like a function
call, users of the macro will tend to place a semi-colon after it.
But because the enclosing braces make it a complete statement, adding
the semi-colon actually produces two statements (the braced one followed
by a null statement). This, in turn, can wreak havoc if users of the
macro do not religiously use braces for all subordinate statements.
E.g.:
if (TRUE)
if (FALSE)
$$IncrementItemPtr_wf(a,b);
else
exit(0);
printf("Surprise!\n");
Since the above code is completely legitimate (other than the indentation),
the compiler will not not complain and you've got a bug that can be
annoying to find.
Although it may seem unbearably ugly, the conventional trick to make
this kind of macro safe to use is to make the enclosing compound statement
a one-trip do-until:
#define $$IncrementItemPtr_wf(_64bitItem,itmlst) \
do { \
\
if (_64bitItem) \
(*((ILEB_64_PQ *) &(itmlst))) ++; \
else \
(*((ILE3_PQ *) &(itmlst))) ++; \
} until 0
By doing this, the macro invocation becomes an incomplete statement
that requires a semi-colon to complete, so the example does not
produce a surprising result. And because the "loop" is easily
analyzed at compile-time as doing nothing, it generates no
additional code.
Another alternative for this particular macro would be to make it
an expression:
#define $$IncrementItemPtr_wf(_64bitItem,itmlst) \
((_64bitItem) ? \
(*((ILEB_64_PQ *) &(itmlst))) ++ \
: \
(*((ILE3_PQ *) &(itmlst))) ++ \
)
This is syntactically safe without the do-until ugliness and can
be used in either expression or statement context, as long as
you're willing to risk possible confusion over whether the
return value is the original (as written) or the incremented value.
|
1298.3 | Did ANSI Really Decide This? | XDELTA::HOFFMAN | Steve, OpenVMS Engineering | Fri May 30 1997 15:34 | 26 |
| :> ((ILE3_PQ)itmlst)++;
...
: ((ILE_PQ)itmlst) = ((ILE_PQ)itmlst) + 1;
...
: (*((ILE3_PQ *) &itmlst)) ++;
Ugh.
ANSI has made some improvements to C, but this new syntax looks
more like a step backwards...
Is "((ILE3_PQ)itmlst)++;" really considered questionable syntax
according to the (intention of the) ANSI standard, or are we
perhaps somewhat overzealous in our lvalue compile-time syntax
checking and reporting?
I can certainly understand
: ((ILE_PQ)itmlst) = ((ILE_PQ)itmlst) + 1;
Being flagged, but preventing:
:> ((ILE3_PQ)itmlst)++;
does reduce the usability of the incrementation operator.
|
1298.4 | If assignment is outlawed, ++ doesn't do anything | WIBBIN::NOYCE | Pulling weeds, pickin' stones | Fri May 30 1997 15:53 | 7 |
| Re .3
Steve, if you accept that the value can't legally be written back,
then what's the difference between
((cast)X)++ and ((cast)X)
or between
++((cast)X) and ((cast)X) + 1
?
|
1298.5 | unary vs lvalues... | XDELTA::HOFFMAN | Steve, OpenVMS Engineering | Fri May 30 1997 16:07 | 40 |
| :Steve, if you accept that the value can't legally be written back,
:then what's the difference between
: ((cast)X)++ and ((cast)X)
:or between
: ++((cast)X) and ((cast)X) + 1
:?
I'd argue that the C language should continue to be smart enough to
do the right thing for situations such as:
char *x;
struct q *foo;
((struct q *)X)->xyz++
...That the compiler and the standard should exempt the unary operators
from the lvalue interpretation of the cast operators. I believe the
above syntax is more concise and is more readable than the ANSI-prefered
`lvalue-compliant' syntax:
char *x;
struct q *foo;
foo = (struct q *) x;
foo->xyz++
or the alternative:
char *x;
struct q *foo;
(*(struct q *) &x)->xyz)++;
With all due respect -- and thanks for the suggestion -- the
syntax:
(*(struct q *) &x)->xyz)++;
is a pretty gross workaround...
|
1298.7 | Hmm... | XDELTA::HOFFMAN | Steve, OpenVMS Engineering | Fri May 30 1997 17:06 | 7 |
| :> ((struct q *)X)->xyz++
:
:There's nothing wrong with this. X is not an lvalue, but
:((cast)X)->xyz is.
I'm not sure which syntactic hair just got split here.
(Off to look at the full source code from .0...)
|
1298.6 | Reposted with typo corrected | WIBBIN::NOYCE | Pulling weeds, pickin' stones | Fri May 30 1997 17:11 | 4 |
| > ((struct q *)X)->xyz++
There's nothing wrong with this. (cast)X is not an lvalue, but
((cast)X)->xyz is.
|
1298.8 | | DECCXL::OUELLETTE | mudseason into blackfly season | Fri May 30 1997 23:14 | 17 |
| Steve, remember that p->f is syntactic sugar for (*p).f.
So casting the lhs of an -> is always OK (as long as you
cast it to a pointer type) because the * over it in the *. form
creates an lvalue.
The usual case of:
int i;
*(short *)&i = 2; // legal
(short) i = 3; // illegal
was mostly there in a lot of compilers long ago.
Note that both cases are non-conformant according to ANSI type
aliasing rules, and such programs must be compiled -assume noansi_alias
or in something less than -std1 to assure correct results.
R.
|
1298.9 | Not sure what's going on... | XDELTA::HOFFMAN | Steve, OpenVMS Engineering | Mon Jun 02 1997 15:08 | 19 |
|
:Steve, remember that p->f is syntactic sugar for (*p).f.
I can assure you I am familiar with -> notation -- I've been
programming in C on OpenVMS since the original VAX C field test,
and I've been resolving VAX C code generation bugs since shortly
after then. :-)
:So casting the lhs of an -> is always OK (as long as you
:cast it to a pointer type) because the * over it in the *. form
:creates an lvalue.
Where I'm having trouble is reconciling what I saw in the source
code -- I suspect there is either a day-one source code bug (and
I'm having trouble believing this error hasn't been detected in
and reported in our source pool before), or that there is some
"odd" syntax here that makes the compiler think this is an illegal
assignment...
|
1298.10 | | SPECXN::DERAMO | Dan D'Eramo | Mon Jun 02 1997 16:56 | 45 |
| >.3
> -< Did ANSI Really Decide This? >-
[...]
> Ugh.
>
> ANSI has made some improvements to C, but this new syntax looks
> more like a step backwards...
>
> Is "((ILE3_PQ)itmlst)++;" really considered questionable syntax
> according to the (intention of the) ANSI standard, or are we
> perhaps somewhat overzealous in our lvalue compile-time syntax
> checking and reporting?
Quotes from X3.159-1989 ... it is the standard that
disallows this.
Dan
Section 3.3.4 Cast Operators, page 46, footnote 44
A cast does not yield an lvalue. [...]
Section 3.3.2.4 Postfix Increment and Decrement Operators, page 43
Constraints
The operand of the postfix increment or decrement
operator shall have qualified or unqualified scalar
type and shall be a modifiable lvalue.
Section 3.3.3.1 Prefix Increment and Decrement Operators, page 44
Constraints
The operand of the prefix increment or decrement
operator shall have qualified or unqualified scalar
type and shall be a modifiable lvalue.
Section 3.3.16 Assignment Operators, page 54
Constraints
An assignment operator shall have a modifiable lvalue
as its left operand.
|
1298.11 | Have you changed /standard? | CXXC::REPETE | Rich Peterson 381-1802 ZKO2-3/N30 | Mon Jun 02 1997 17:42 | 3 |
| This warning is suppressed under /standard=vaxc or /standard=common.
Have you been trying to clean up your code base by compiling in
relaxed ansi mode?
|