casts and lvalues

M

Mark McIntyre

if I would add support for it, are there any TECHNICAL drawbacks?

I guess the point is, nobody commenting here can currently see any
actual purpose for adding it. Before asking if there are any technical
drawbacks, one needs to first ascertain a use.

Imagine you're a car designer. Do you ask "is there a technical
drawback with adding a beach umbrella on the steering wheel?" or do
first you ask why....
--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
 
M

Mark McIntyre

(replying to Jabob's comment)


C constructs are no natural phenomena. They are meaningful if people
assign meaning to them.

Philosophy is all very well...
And several compilers *have* assigned meaning
to casts as lvalues,

Yes, but the point is in my view that meaning is meaningless.
IYSWIM...
I believe that it's intended to be equivalent to "a = (long long)n'.
As such, it's not very useful.

Quite

--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
 
J

Joe Wright

jacob said:
Keith said:
jacob navia said:
Continuing the discussion about casts, I would like to know
your opinions about the hairy subject of casts as lvalues, i.e.

int main(void)
{
long long a;
char *n;
(char *)a = n;
}
This will fail under lcc-win32, but MSVC and gcc will
accept it. I know that the standard prescribes the behavior
that lcc-win32 uses, but I left that behavior after a big
discussion about this several years ago. I had modified it,
and some people raised hell.

What are the problems of doing this? I mean not the usual
"the standard says so" but what problems would arise within the
language if this would be accepted?
[...]

This extension doesn't seem to me to be particularly useful. The
above would be more clearly written as:

long long a;
char *n;
a = (long long)n;

Granted.

It is clearer but the question is not if this is pleasing but if there
would be any problems (in the sense of contradictions or buggy language
specifications) if casts could be lvalues.
Another problem with this, as with any extension, is that it
encourages programmers to write non-portable code that depends on it.

Yes, of course. lcc-win32 doesn't even support this extension. But
if I would add support for it, are there any TECHNICAL drawbacks?
I mean, if somebody asks me to support overloading addition
with

int operator+(struct FOO *a,int b);

I would say NO that can't be done because addition of a pointer and
an integer is already used in the language to access the nth element
using a pointer as base, i.e.
struct FOO *p;
p + 6
addresses the sixth element after the element pointed by p. If I would
implement such an extension I would introduce an ambiguity in the
language.

Is that the case with casts as lvalues?
Well, an lvalue expression tells us where the object is so that we might
store a value there. The current value stored in the object may be of no
interest at all. Let's imagine we have two 4-byte int objects in memory
at address 200.

200 : int a
204 : int b

Neither a nor b is initialized. Their values are indeterminate.

a = 1;

The expression a is an lvalue because the compiler knows it's at 200 and
so knows where to store the value 1.

b = a;

The expression b is an lvalue at address 204. The expression a is now
simply the value 1 to be stored in the location defined by lvalue b.

In C, a cast is an explicit conversion of a value from one type to
another. The result is a value of the destination type. What would we
expect of..

(short)a = b:

...whether gcc 'allows' it or not? C89 apparently does not allow it.
 
C

CBFalconer

Richard said:
CBFalconer said:

No, it doesn't. No object is converted by a cast, and casts do not
*require* lvalues to receive their results. For example, there is
no lvalue in the (pointless but legal) statement:

toupper((unsigned char)c);

Yes there is, although it is well hidden. The functional parameter.
 
R

Richard Heathfield

CBFalconer said:
Yes there is, although it is well hidden. The functional parameter.

No, it isn't well hidden. It isn't *there*. Not in that statement.
 
S

Stephen Sprunk

Joe Wright said:
Well, an lvalue expression tells us where the object is so that we might
store a value there. The current value stored in the object may be of no
interest at all. Let's imagine we have two 4-byte int objects in memory at
address 200. ....
In C, a cast is an explicit conversion of a value from one type to
another. The result is a value of the destination type. What would we
expect of..

(short)a = b:

..whether gcc 'allows' it or not? C89 apparently does not allow it.

Logically, it would be equivalent to (i.e. shorthand for) the expression:

*(short *)&a = b;

However, doing that is generally a bad idea for several different reasons,
and I am philosophically opposed to making bad ideas easier to express.
They should stand out in code, not be made invisible.

There's also the argument that most of the features added in C99 were
extensions that were widely implemented and oconsidered to add value; given
that the GCC folks initially implemented but then deprecated this feature,
and GCC is one of the most widely used compilers, that doesn't bode well for
this being added to the next revision of C. It also doesn't appear to add
any value, since you can already accomplish the same bad idea today if you
really want to.

S
 
C

CBFalconer

Richard said:
CBFalconer said:

No, it isn't well hidden. It isn't *there*. Not in that statement.

We must be missing each others points. Where do you think the
conversion of c goes? All the elements of the library have to be
available as functions, and macros (if provided) can only mimic a
function call.
 
D

Dik T. Winter

> On Sun, 24 Jun 2007 21:13:40 +0200, jacob navia

>
> What do you do with:
> (char *)(3LL + 5LL) = n;
> ...???

More interesing:
char a;
(long *) a = 0;
Or in general, what if a cast changes the representation?
 
R

Richard Heathfield

CBFalconer said:
We must be missing each others points. Where do you think the
conversion of c goes?

It could easily go into a register, but that's beside the point. There's
no object in the statement I presented.
All the elements of the library have to be
available as functions, and macros (if provided) can only mimic a
function call.

Yes, but the statement I presented is not a function definition. It is
merely a function call.
 
K

Keith Thompson

CBFalconer said:
We must be missing each others points. Where do you think the
conversion of c goes? All the elements of the library have to be
available as functions, and macros (if provided) can only mimic a
function call.

There's an lvalue in the expression, but not the one that anyone has
mentioned. Assuming c is a declared object, c (the argument of the
cast) is an lvalue; it's just not used in a context that requires an
lvalue, so it's converted to a non-lvalue, yielding the current value
of c. (I don't remember where the standard specifies this
conversion.)

The *parameter* of the toupper function is an object, and a reference
to that object is an lvalue, but any such reference can only be within
the definition of the toupper function; it's not on the line in
question. In the call, we merely have an *argument*, which is just an
expression (that doesn't happen to be an lvalue).

Note that the identifier toupper itself is not an lvalue, since it
designates a function, not an object.

(If toupper is defined as a macro, then the expression to which the
call expands could include any number of lvalues.)

As for the proposed extension, I presume that a cast expression would
be an lvalue if and only if the operand is an lvalue.
 
R

Richard Bos

Mark McIntyre said:
I guess the point is, nobody commenting here can currently see any
actual purpose for adding it. Before asking if there are any technical
drawbacks, one needs to first ascertain a use.

Imagine you're a car designer. Do you ask "is there a technical
drawback with adding a beach umbrella on the steering wheel?" or do
first you ask why....

jacob might want to ponder this quotation from a superior specimen among
his compatriots:

La perfection est atteinte non quand il ne reste rien à ajouter,
mais quand il ne reste rien à enlever.

Richard
 
J

jacob navia

Richard said:
CBFalconer said:

It could easily go into a register, but that's beside the point. There's
no object in the statement I presented.

The result of the expression is stored in the stack.
(Or its equivalent for the mythical machines without
stack)

The object exists, since we can even take its address
within the called function.
 
J

jacob navia

Stephen said:
Logically, it would be equivalent to (i.e. shorthand for) the expression:

*(short *)&a = b;

However, doing that is generally a bad idea for several different
reasons, and I am philosophically opposed to making bad ideas easier to
express. They should stand out in code, not be made invisible.

There's also the argument that most of the features added in C99 were
extensions that were widely implemented and oconsidered to add value;
given that the GCC folks initially implemented but then deprecated this
feature, and GCC is one of the most widely used compilers, that doesn't
bode well for this being added to the next revision of C. It also
doesn't appear to add any value, since you can already accomplish the
same bad idea today if you really want to.

S


Thanks for your answer.

lcc-win32 does NOT support this gcc extension, but when speaking about
casts in my tutorial I wanted to EXPLAIN why it is a bad idea...
Users will discover this eventually, and an explanation is necessary.
 
K

Keith Thompson

jacob navia said:
The result of the expression is stored in the stack.
(Or its equivalent for the mythical machines without
stack)

Mythical? Real-world examples of such machines have been discussed in
this newsgroup.
The object exists, since we can even take its address
within the called function.

Yes, *within* the called function. The object (the parameter) doesn't
exist outside the function; it's a local object with automatic storage
duration.
 
J

jacob navia

Keith said:
Mythical? Real-world examples of such machines have been discussed in
this newsgroup.


Yes, *within* the called function. The object (the parameter) doesn't
exist outside the function; it's a local object with automatic storage
duration.

Thanks. You agree with me then, that the object exists, and exists
before the call, even if it is not accessible.

This is obvious if we read the standard 6.5.2.2 "Function calls", where
it is specified that after all assignments are done to the function
arguments there is a sequence point. At that sequence point the
arguments have been assigned but they are still not accessible since the
function call is not done yet.

Obviously the objects exist within the function call. They have a
constant address, and they retain their last assigned value.
 
R

Richard Heathfield

jacob navia said:

(I misspoke. The c object is clearly an object!)
The result of the expression is stored in the stack.
(Or its equivalent for the mythical machines without
stack)

Or a register, or in some part of memory, or on disk, or on tape, or on
a piece of paper. The C Standard imposes no requirement on
implementations to store the results of expressions on a stack, not
even for implementations that use stacks.
The object exists, since we can even take its address
within the called function.

The implementation *may* create an object *as a result of* the toupper
call, but the result of the expression (unsigned char)c is not an
lvalue just because the implementation does exercise its licence to
create an object to store it during the execution of toupper.

If that /were/ true, then the result of the expression (unsigned
char)(6+42) would also be an lvalue.
 
K

Keith Thompson

jacob navia said:
lcc-win32 does NOT support this gcc extension, but when speaking about
casts in my tutorial I wanted to EXPLAIN why it is a bad idea...
Users will discover this eventually, and an explanation is necessary.

(The extension being discussed is allowing casts as lvalues.)

You're writing a tutorial about C, right? C doesn't allow casts as
lvalues. Why even mention it?
 
R

Richard Heathfield

jacob navia said:
Thanks. You agree with me then, that the object exists, and exists
before the call, even if it is not accessible.

No, he doesn't, and neither do I. As he rightly said, the object doesn't
exist until the function is called (if indeed a function *is* called
for the expression under consideration, which is not necessarily the
case). It's a local object with automatic storage duration, so it
doesn't exist until the function call actually happens.
This is obvious if we read the standard 6.5.2.2 "Function calls",
where it is specified that after all assignments are done to the
function arguments there is a sequence point. At that sequence point
the arguments have been assigned but they are still not accessible
since the function call is not done yet.

Two problems with this - firstly, you're trying to nudge the discussion
further and further into the called function in an attempt to shore up
your case, but we're discussing the cast-expression, not the execution
details of the called function; and secondly, there isn't necessarily a
function call at all! The expression, remember, was toupper((unsigned
char)c), and the implementation is perfectly at liberty to convert this
into something like:
(((unsigned char)c) == EOF) ? EOF : __toupper[((unsigned char)c)]

where __toupper is an array in read-only memory.

*Now* where is your lvalue?
Obviously the objects exist within the function call. They have a
constant address, and they retain their last assigned value.

Until the function (if there /is/ a function) returns, yes.
 
K

Keith Thompson

jacob navia said:
Thanks. You agree with me then, that the object exists, and exists
before the call, even if it is not accessible.

I didn't say that, but I agree, more or less.
This is obvious if we read the standard 6.5.2.2 "Function calls",
where it is specified that after all assignments are done to the
function arguments there is a sequence point. At that sequence point
the arguments have been assigned but they are still not accessible
since the function call is not done yet.

Obviously the objects exist within the function call. They have a
constant address, and they retain their last assigned value.

An *argument* is not an object. An argument is an expression
appearing between the parentheses in a function call; see C99 3.3.
A *parameter* is an object; see C99 3.15. Please keep the
terminology straight.

The standard is a bit vague, and perhaps even contradictory, about
the lifetime of a parameter. See C99 6.5.2.2p4:

An argument may be an expression of any object type. In preparing
for the call to a function, the arguments are evaluated, and each
parameter is assigned the value of the corresponding argument.

implying that a parameter is created before the function is called.
But C99 6.9.1p9 says:

Each parameter has automatic storage duration. Its identifier is
an lvalue, which is in effect declared at the head of the compound
statement that constitutes the function body (and therefore cannot
be redeclared in the function body except in an enclosed block).

which implies that the parameter object isn't created until control
passes the opening '{' of the function.

I'm not suggesting that this is a real problem in the standard, just
that it's difficult to say whether a parameter object exists before
the function is called.

But in any case, the question from upthread is whether this statement:

toupper((unsigned char)c);

contains an lvalue. c is an lvalue, but (unsigned char)c is not, and
statement does *not* contain an lvalue that refers to the parameter.
 

Ask a Question

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

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

Ask a Question

Similar Threads

Casts on lvalues 74
Casts 81
Union and pointer casts? 13
casts and pointers 0
Pointer casts for OOP 2
sub-int types, casts, MISRA and RH's writings 6
Question about casts 7
Pointer to Structure Casts 5

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top