Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #9969 > unrolled thread
| Started by | Quentin Pope <qp19433@hotmail.NOSPAM.com> |
|---|---|
| First post | 2011-09-06 21:01 +0000 |
| Last post | 2011-09-06 18:33 -0700 |
| Articles | 5 — 4 participants |
Back to article view | Back to comp.lang.c
Another Union question Quentin Pope <qp19433@hotmail.NOSPAM.com> - 2011-09-06 21:01 +0000
Re: Another Union question James Kuyper <jameskuyper@verizon.net> - 2011-09-06 17:44 -0400
Re: Another Union question Ben Bacarisse <ben.usenet@bsb.me.uk> - 2011-09-07 02:08 +0100
Re: Another Union question James Kuyper <jameskuyper@verizon.net> - 2011-09-07 08:04 -0400
Re: Another Union question Keith Thompson <kst-u@mib.org> - 2011-09-06 18:33 -0700
| From | Quentin Pope <qp19433@hotmail.NOSPAM.com> |
|---|---|
| Date | 2011-09-06 21:01 +0000 |
| Subject | Another Union question |
| Message-ID | <j461mk$pcu$1@speranza.aioe.org> |
We know that &struct is equiv to &struct.firstMember. So far so good.
Now I have an union
union r32{
uint8 l;
uint16 x;
uint32 val;
};
union r32 reg;
and a function
void f(union r32* a){a->x=1;}
then
is to do f(®.x) or f(®.l) or f(®.val) OK or not?
is it ®.x=®.l=®.val ?
Or I have to do f(®)?
[toc] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2011-09-06 17:44 -0400 |
| Message-ID | <4E669424.6070908@verizon.net> |
| In reply to | #9969 |
On 09/06/2011 05:01 PM, Quentin Pope wrote:
> We know that &struct is equiv to &struct.firstMember. So far so good.
Not true. Those two pointers have different types, and correspondingly
different behavior when dereferenced, so they are not equivalent. A more
accurate statement would be
(firstmember_type*)&struct == &struct.firstMember
and also:
&struct == (struct struct_tag*)&struct.firstMember
Note: if firstMember is a bit-field, &struct.firstMember is a constraint
violation, and these guarantees don't hold.
> Now I have an union
> union r32{
> uint8 l;
> uint16 x;
> uint32 val;
If you're using C99, you should #include <stdint.h> and replace these
with uint8_t, uint16_t, uint32_t. These types are not guaranteed to be
supported, though they should in fact be supported on almost all
implementations. If a serious C99 implementation does not provide those
types on given platform, you can reasonably assume that it's extremely
difficult, perhaps even impossible, to provide those types on that
platform. You can check whether or not they are supported by
#if !defined(UINT8_MAX) || !defined(UINT16_MAX) || !defined(UINT32_MAX)
#error uint8_t, uint16_t or uint32_t not supported.
#endif
> };
>
> union r32 reg;
>
> and a function
> void f(union r32* a){a->x=1;}
>
> then
>
> is to do f(®.x) or f(®.l) or f(®.val) OK or not?
With a function prototype in scope, all of those pointers are implicitly
converted to union r32* when passed to that function. The result of that
conversion is guaranteed to point at the containing union, so all three
are OK.
> is it ®.x=®.l=®.val ?
No, but
(union r32*)®.x == (union r32*)®.l
and similarly for the other combinations. It's also true that
(uint32*)(union r32*)®.x == ®.val
It would seem obvious that this means that
(uint32*)®.x == ®.val
and this is indeed true on (almost?) all implementations of C. However,
the standard does not actually guarantee that (uint32*)(union r32*)
produces the same result as (uint32*).
> Or I have to do f(®)?
While you do not have to use ®, I would strongly recommend it unless
you have a compelling need to use something else.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2011-09-07 02:08 +0100 |
| Message-ID | <0.0c8797be815ceed52054.20110907020845BST.87vct540rm.fsf@bsb.me.uk> |
| In reply to | #9972 |
James Kuyper <jameskuyper@verizon.net> writes:
> On 09/06/2011 05:01 PM, Quentin Pope wrote:
<snip>
>> Now I have an union
>> union r32{
>> uint8 l;
>> uint16 x;
>> uint32 val;
<snip>
>> union r32 reg;
>>
>> and a function
>> void f(union r32* a){a->x=1;}
>>
>> then
>>
>> is to do f(®.x) or f(®.l) or f(®.val) OK or not?
>
> With a function prototype in scope, all of those pointers are implicitly
> converted to union r32* when passed to that function. The result of that
> conversion is guaranteed to point at the containing union, so all three
> are OK.
That's not right. It's a constraint violation if an argument has a type
that means it could not be assigned to an object with the (unqualified)
version of the parameter type.
Because it's a constraint, there must be a diagnostic and the program
will have undefined behaviour. Many implementation take that as
permission to go on and translate the unit as if a cast had been used to
specify the conversion, but that's not in any way required or
guaranteed.
<snip>
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2011-09-07 08:04 -0400 |
| Message-ID | <j47mkc$klr$1@dont-email.me> |
| In reply to | #9977 |
On 09/06/2011 09:08 PM, Ben Bacarisse wrote:
> James Kuyper <jameskuyper@verizon.net> writes:
>
>> On 09/06/2011 05:01 PM, Quentin Pope wrote:
> <snip>
>>> Now I have an union
>>> union r32{
>>> uint8 l;
>>> uint16 x;
>>> uint32 val;
> <snip>
>>> union r32 reg;
>>>
>>> and a function
>>> void f(union r32* a){a->x=1;}
>>>
>>> then
>>>
>>> is to do f(®.x) or f(®.l) or f(®.val) OK or not?
>>
>> With a function prototype in scope, all of those pointers are implicitly
>> converted to union r32* when passed to that function. The result of that
>> conversion is guaranteed to point at the containing union, so all three
>> are OK.
>
> That's not right. It's a constraint violation if an argument has a type
> that means it could not be assigned to an object with the (unqualified)
> version of the parameter type.
You're right - I don't know how I managed to forget that. It is
therefore not merely pointless, but just plain wrong, to use any of
those expressions.
f((union r32*)®.x) would, however, be a perfectly fine, though
pointlessly complicated, way of writing f(®). If taken as short-hand
for something that happens in two different stages in widely separated
scopes, it actually becomes more reasonable:
void g(uint16 *pui16)
{
f((union r32*)pui16));
}
In some other function:
g(®.x);
--
James Kuyper
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2011-09-06 18:33 -0700 |
| Message-ID | <lnhb4pp25c.fsf@nuthaus.mib.org> |
| In reply to | #9972 |
James Kuyper <jameskuyper@verizon.net> writes:
> On 09/06/2011 05:01 PM, Quentin Pope wrote:
[...]
>> Now I have an union
>> union r32{
>> uint8 l;
>> uint16 x;
>> uint32 val;
[...]
>> };
>>
>> union r32 reg;
>>
>> and a function
>> void f(union r32* a){a->x=1;}
>>
>> then
>>
>> is to do f(®.x) or f(®.l) or f(®.val) OK or not?
>
> With a function prototype in scope, all of those pointers are implicitly
> converted to union r32* when passed to that function. The result of that
> conversion is guaranteed to point at the containing union, so all three
> are OK.
[...]
There is no implicit conversion from a pointer-to-integer type to a
pointer-to-union type. An explicit conversion (a cast) should work ok:
f((union r32*)®.x);
f((union r32*)®.x);
f((union r32*)®.val);
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c
csiph-web