Jef Driesen
5/16/2011 7:54:00 PM
On 16/05/11 21:43, Shao Miller wrote:
> On 5/16/2011 14:55, Jef Driesen wrote:
>> On 16/05/11 20:38, Shao Miller wrote:
>>> On 5/16/2011 14:06, Jef Driesen wrote:
>>>> Suppose I have defined a union:
>>>>
>>>> typedef struct foo_t {
>>>> ...
>>>> } foo_t;
>>>>
>>>> typedef struct bar_t {
>>>> ...
>>>> } bar_t;
>>>>
>>>> typedef union foobar_t {
>>>> foo_t foo;
>>>> bar_t bar;
>>>> } foobar_t;
>>>>
>>>> Which is part of the public api of my project.
>>>
>>> As in, these are in a header file and the struct and union definitions
>>> will thus be available within all users' translation units, assuming
>>> they include the header?
>>
>> Yes. How would they be able to use it otherwise?
>
> I didn't (and don't) understand your "the union itself appears only in
> the implementation (e.g. in the dosomething() function)". What about it
> only appears in the private TUs and not in the public headers?
>
> [ Corrected typographical errors below. Not sure why indenting dies
> with this news client. Sorry. ]
>>
>>>> The union is used to pass
>>>> different types of data (e.g. either a foo or a bar struct) back to the
>>>> caller through a callback function. The type is used distinguish between
>>>> the two:
>>>>
>>>> typedef enum foobar_type_t {
>>>> FOO,
>>>> BAR,
>>>> } foobar_type_t;
>>>>
>>>> typedef void (*callback_t)(foobar_type_t type, const foobar_t *foobar);
>>>>
>>>> void
>>>> dosomething (callback_t callback)
>>>> {
>>>>
>>>> foobar_t foobar;
>>>>
>>>> foobar.foo = ...
>>>> callback (FOO,&foobar);
>>>>
>>>> foobar.bar = ...
>>>> callback (BAR,&foobar);
>>>> }
>>>>
>>>> Note that I only use pointers to the union in the public api. The union
>>>> itself appears only in the implementation (e.g. in the dosomething()
>>>> function).
>>>>
>>>
>
> The union definition?
> ---
> /* public.h */
> ...
> typedef union foobar_t foobar_t;
> ...
> ---
> /* private.c */
> ...
> typedef union foobar_t {
> foo_t foo;
> bar_t bar;
> } foobar_t;
> ...
> ---
>
> Or is the definition in public.h?
In public.h, because if not I see no advantage in the union compared to using a
void pointer (instead of pointer to the union) together with the individual structs.
>>>> Now suppose I need to extend my api to support a third type of data. Is
>>>> it portable to just add a third struct to the union? Will it break the
>>>> ABI rules and thus backwards compatibility. Is this a violation of the C
>>>> standard?
>>>>
>>>
>>> From n1256.pdf, section 6.2.5, point 27:
>>>
>>> "...All pointers to union types shall have the same representation
>>> and alignment requirements as each other..."
>>>
>>> :)
>>>
>>>> The alternative would be to use a void pointer and require the user to
>>>> cast to the appropriate data type,
>>>
>>> No need to cast a 'void *' to another pointer-to-object type.
>>
>> I know, but if it's not assigned to another variable, but converted
>> on-the-fly like below I don't think you can avoid the cast.
>>
>
> Above, you have already shown:
>
> foobar->foo.xyz
>
> So why cast?
>
> [ Corrected typographical errors below. ]
>>>> but this is less readable:
>>>>
>>>> foobar->foo.member
>>>>
>>>> vs
>>>>
>>>> ((foo_t *)foobar)->member
>>>
>
> Really? I prefer the former, personally.
I think there is a little misunderstand here. I also prefer the first version.
But this is of course only possible with the union (e.g. foobar is a pointer to
the union). Without the union, foobar would be a void pointer and needs to be
cast to a pointer to the appropriate struct (e.g. foo_t). And that's the second
version above.
> If you come up with version 2.0 of the "public.h" header and it includes
> a new structure in the union, that structure could affect the alignment
> requirements of the union.
>
> If the only code that allocates such union objects is aware of the
> change, the alignment requirements should still satisfy the old union
> version, as long as you don't remove the old struct members, right?
>
> I wouldn't expect that other users' code would care... Their foos and
> bars are still aligned, and 'foo_t' and 'bar_t' still has the same tag
> and same definition[n1256.pdf:6.2.7p1]. I'd view the use of a "newer"
> union rather than the "outdated" union as "type-punning", under these
> circumstances. I could be mistaken.
I'm not sure either, that's why I'm asking :-)