Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Casts on lvalues

Reply
Thread Tools

Casts on lvalues

 
 
Keith Thompson
Guest
Posts: n/a
 
      12-06-2012
"BartC" <> writes:
[...]
> So this statement:
>
> "Keith Thompson" <kst-> wrote in message
> news:...
>
>> C doesn't have lvalue casts.

>
> isn't completely true, because it seems you can get around it easily by
> turning it into an rvalue cast first. (Also I'm talking about type-punning
> sorts of casts rather than type-conversion ones.)


Yes, it is completely true.

C doesn't have linked lists or binary trees either, but you can
easily implement them using structs and pointers. C gives you the
basic tools needed to build just about *anything*. Lvalue casts
(whatever you happen to mean by that phrase) are not one of those
basic tools, but they are something you can build.

And please keep in mind that there's a *big* difference between
conversion and type-punning. Conversion, as implemented by
a cast operator, converts a *value* from one type to another.
For example, a conversion from int to float gives you a float
with the mathematical value of the operand, regardless of how ints
and floats are represented. Pointer conversions conceptually do
the same thing; it just happens that most modern implementations
represent all pointers the same way, so pointer conversions can be
implemented as a reinterpretation of the representation.

--
Keith Thompson (The_Other_Keith) kst- <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
 
 
 
Piotr Kalinowski
Guest
Posts: n/a
 
      12-06-2012
"BartC" <> writes:

> "Ian Collins" <ian-> wrote in message
> news:...
> But, I can do the equivalent of ++(char*)P by writing:
>
> P = (int*)((char*)P+1);
>
> (or near enough if that's not quite right.) So the world can still end.


It's not about disallowing you to shoot yourself. It's about making it
more difficult, so you're slightly less likely to do it. It's about
increasing the cost of ending the world, so that you'll think twice
(hopefully) before doing it.

Regards,
Piotr Kalinowski
 
Reply With Quote
 
 
 
 
Philipp Thomas
Guest
Posts: n/a
 
      12-07-2012
On Wed, 05 Dec 2012 16:09:23 -0800, Keith Thompson <kst->
wrote:

>Or you can use a union; this avoids alignment issues, but the other
>problems still apply.


When used for type-punning that isn't guaranteed to work but depends
on the compiler.

>Or you can use memcpy() to create a *copy* of an object's representation
>in an object of a different type.


And this is the only clean way to fix type-punning and avoid alignment
issues.

Philipp
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      12-07-2012
Philipp Thomas <> writes:
> On Wed, 05 Dec 2012 16:09:23 -0800, Keith Thompson <kst->
> wrote:
>>Or you can use a union; this avoids alignment issues, but the other
>>problems still apply.

>
> When used for type-punning that isn't guaranteed to work but depends
> on the compiler.


A footnote in the standard (N1370 6.5.2.3p3, footnote 95) says:

If the member used to read the contents of a union object is
not the same as the member last used to store a value in the
object, the appropriate part of the object representation of
the value is reinterpreted as an object representation in the
new type as described in 6.2.6 (a process sometimes called
"type punning"). This might be a trap representation.

I'm not sure why that's stated only in a non-normative footnote.
I suppose the implication is that it's already stated normatively,
but it's not clear to me that it is.

In any case, a union does avoid alignment issues.

>>Or you can use memcpy() to create a *copy* of an object's representation
>>in an object of a different type.

>
> And this is the only clean way to fix type-punning and avoid alignment
> issues.


--
Keith Thompson (The_Other_Keith) kst- <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Philip Lantz
Guest
Posts: n/a
 
      12-07-2012
BartC wrote:
>
> "Ben Bacarisse" <> wrote in message
> news:0.9fd76eb692e0db06bfc4.20121205220731GMT.87mw ...
> > "BartC" <> writes:
> >
> >> "Eric Sosman" <> wrote in message
> >> news:k9o2b3$bcb$...

> > <snip>
> >>> Um, er, assignment itself is asymmetric ...
> >>
> >> Plenty of terms can appear interchangeably on both left and right sides.
> >>
> >> But while A can appear on either side, (T)A can't. And there doesn't
> >> appear to be a convincing reason why not.

> >
> > B = (T)A; // OK
> > (T)A = B; // not OK
> > B = +A; // OK
> > +A = B; // not OK
> > B = !A; // OK
> > !A = B; // not OK
> > B = A + C; // OK
> > A + C = B; // not OK
> >
> > ... and so on. There's a pattern.

>
> OK, I see it. But: the (T)A=B example might be done instead as:
>
> memcpy(&A, &B, sizeof(T));
>
> So it expresses something that could conceivably make sense. Unlike the
> other examples that don't!


Do you think that "B = (T)A" is similar to "memcpy(&B, &A, sizeof(T))"?

It's not.

So, if you did think that, it helps me understand why you think lvalue
casts make sense.
 
Reply With Quote
 
Öö Tiib
Guest
Posts: n/a
 
      12-07-2012
On Friday, 7 December 2012 03:22:47 UTC+2, Keith Thompson wrote:
> Philipp Thomas <> writes:
> > On Wed, 05 Dec 2012 16:09:23 -0800, Keith Thompson <kst->
> > wrote:
> >>Or you can use a union; this avoids alignment issues, but the other
> >>problems still apply.

> >
> > When used for type-punning that isn't guaranteed to work but depends
> > on the compiler.

>
> A footnote in the standard (N1370 6.5.2.3p3, footnote 95) says:
>
> If the member used to read the contents of a union object is
> not the same as the member last used to store a value in the
> object, the appropriate part of the object representation of
> the value is reinterpreted as an object representation in the
> new type as described in 6.2.6 (a process sometimes called
> "type punning"). This might be a trap representation.
>
> I'm not sure why that's stated only in a non-normative footnote.
> I suppose the implication is that it's already stated normatively,
> but it's not clear to me that it is.


C99 has such texts:

6.2.5p20, union has an overlapping set of member objects
6.7.2.1p14, the value of at most one of the members can be stored in a union object at any time
Annex J.1 the value of a union member other than the last one stored into is unspecified.

I do not feel it safe to use union for type punning.
 
Reply With Quote
 
BartC
Guest
Posts: n/a
 
      12-07-2012
"Philip Lantz" <> wrote in message
news:...
> BartC wrote:
>>
>> "Ben Bacarisse" <> wrote in message
>> news:0.9fd76eb692e0db06bfc4.20121205220731GMT.87mw ...


>> > B = (T)A; // OK
>> > (T)A = B; // not OK


>> OK, I see it. But: the (T)A=B example might be done instead as:
>>
>> memcpy(&A, &B, sizeof(T));
>>
>> So it expresses something that could conceivably make sense. Unlike the
>> other examples that don't!

>
> Do you think that "B = (T)A" is similar to "memcpy(&B, &A, sizeof(T))"?


No. I'm interested in type-punning the left-hand-side; memcpy might be one
way of achieving that in some cases.

Your example might also work, except that (T) on the right-hand-side does
type conversion not type-punning.

> It's not.
>
> So, if you did think that, it helps me understand why you think lvalue
> casts make sense.


Since any 'lvalue cast' of the form (T)A can be written instead as *(T*)&A,
which is perfectly legal, then why shouldn't it make sense?

Look, I have this compiler project from a couple of months back. That
language also doesn't have lvalue casts (it wasn't too hot on casts, but it
*does* have the 'equivalence' feature which C doesn't have, which is what is
used instead, and is better IMO).

I decided to add lvalue casts to that language. It took ten minutes, and six
lines of code, to have them working for assignment! (Needs a bit more work
for general lvalues, and obviously a lot more testing.)

So I can now write in that language:

real x
int a

a:=x
real(a):=x # lvalue cast!

Intermediate output:

0003: 1:005 convert (a,x) int32,
real64
0004: 1:006 move (a,x)
real64, real64

And, since it was set up to produce C code, this is the final output
(obviously r64 and i32 are typedefs):

r64 x;
i32 a;

a = x;
*(r64*)&a = x;

Notice anything similar between this last line (which I haven't doctored)
and the *(T*)&A I wrote above? (I didn't even change any part of the code
generation; this is what naturally came out. However, I didn't run this
example because I just realised the destination is too small..)

Lvalue casts *can* be meaningful, and while people are right in that C
doesn't directly define them, they can be achieved with a simple
transformation.

--
Bartc

 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      12-07-2012
On 12/07/2012 03:31 AM, � wrote:
> On Friday, 7 December 2012 03:22:47 UTC+2, Keith Thompson wrote:
>> Philipp Thomas <> writes:
>>> On Wed, 05 Dec 2012 16:09:23 -0800, Keith Thompson <kst->
>>> wrote:
>>>> Or you can use a union; this avoids alignment issues, but the other
>>>> problems still apply.
>>>
>>> When used for type-punning that isn't guaranteed to work but depends
>>> on the compiler.

>>
>> A footnote in the standard (N1370 6.5.2.3p3, footnote 95) says:
>>
>> If the member used to read the contents of a union object is
>> not the same as the member last used to store a value in the
>> object, the appropriate part of the object representation of
>> the value is reinterpreted as an object representation in the
>> new type as described in 6.2.6 (a process sometimes called
>> "type punning"). This might be a trap representation.
>>
>> I'm not sure why that's stated only in a non-normative footnote.
>> I suppose the implication is that it's already stated normatively,
>> but it's not clear to me that it is.

>
> C99 has such texts:
>
> 6.2.5p20, union has an overlapping set of member objects
> 6.7.2.1p14, the value of at most one of the members can be stored in a union object at any time
> Annex J.1 the value of a union member other than the last one stored into is unspecified.
>
> I do not feel it safe to use union for type punning.


Keep in mind that footnote 95 merely describes what the committee
intended to be the case from the very beginning, and what is easiest to
implement, and what virtually every real implementation of C always has
implemented, because a great many C programmers have always assumed it
was true. It's not really worthwhile worrying about the possibility that
a union won't work as described by footnote 95. There's much better
things to worry about - such as the fact that type punning inherently
requires building into your code implementation-specific knowledge about
how the two types are represented.


--
James Kuyper
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      12-07-2012
On 12/07/2012 07:54 AM, BartC wrote:
....
> Look, I have this compiler project from a couple of months back. That
> language also doesn't have lvalue casts (it wasn't too hot on casts, but it
> *does* have the 'equivalence' feature which C doesn't have, which is what is
> used instead, and is better IMO).


C does have a feature with the same semantics as your "equivalence"
feature, just different syntax. That feature is called a union.
--
James Kuyper
 
Reply With Quote
 
BartC
Guest
Posts: n/a
 
      12-07-2012


"James Kuyper" <> wrote in message
news:k9sqi4$do2$...
> On 12/07/2012 07:54 AM, BartC wrote:
> ...
>> Look, I have this compiler project from a couple of months back. That
>> language also doesn't have lvalue casts (it wasn't too hot on casts, but
>> it
>> *does* have the 'equivalence' feature which C doesn't have, which is what
>> is
>> used instead, and is better IMO).

>
> C does have a feature with the same semantics as your "equivalence"
> feature, just different syntax. That feature is called a union.


Unions are much more limited. For example, if you have:

int A[25];
double X;

you can't 'equivalence' X to A[16] without some difficulty. (Actually X
might span both A[16] and A[17].)

A might also be external, limiting the options further.

It's also harder to refer to A and X entirely independently; you might need
to use U.A and U.X (if you can even get that far).

(BTW 'equivalence' is a (now-deprecated) feature of Fortran. I thought
people might be familiar with it. My version just uses @, for example:
double X @ A[16]; )

--
Bartc

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
— conversion of array to pointer not limited to lvalues nicolas.sitbon@gmail.com C Programming 18 08-06-2008 04:41 PM
casts and lvalues jacob navia C Programming 68 06-27-2007 03:32 PM
Lvalues and Rvalues ramasubramanian.rahul@gmail.com C Programming 3 10-14-2006 09:55 PM
Avoiding "use of cast expressions in lvalues is deprecated" steve.j.donovan@gmail.com C Programming 23 09-21-2006 05:45 PM
lvalues -> incomplete types Mantorok Redgormor C Programming 7 02-07-2004 03:45 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57