分享

transparent union type attribute

 hginvent 2013-07-24

__attribute__((transparent_union)) type attribute

The transparent_union type attribute enables you to specify a transparent_union type, that is, a union data type qualified with __attribute__((transparent_union))__.

When a function is defined with a parameter having transparent union type, a call to the function with an argument of any type in the union results in the initialization of a union object whose member has the type of the passed argument and whose value is set to the value of the passed argument.

When a union data type is qualified with __attribute__((transparent_union)), the transparent union applies to all function parameters with that type.

Note

This type attribute is a GNU compiler extension that is supported by the ARM compiler.

Note

Individual function parameters might also be qualified with the corresponding __attribute__((transparent_union)) variable attribute.

Show/hideExample

typedef union { int i; float f; } U __attribute__((transparent_union));
void foo(U u)
{
    static int s;
    s += u.i;    /* Use the 'int' field */
}
void caller(void)
{
    foo(1);        /* u.i is set to 1 */
    foo(1.0f);     /* u.f is set to 1.0f */
}

Show/hideMode

Supported in GNU mode only.


StrongSwan大量引用tranparent union来避免pointer cast带来的烦恼,在strongswan的FAQ中写到:


Work-Item: Avoid function pointer casts

Branch: nocast

Schedule: 4.3.6/4.4.0

Rationale:
The object paradigm of the strongSwan source code makes heavy use of
function pointers. As the "this" parameter is passed as a pointer to the
implementing interface, but the function expects a pointer to the
private interface implementation, a cast is required.
strongSwan traditionally uses a cast of the function pointer during
object initialization. But this has several disadvantages:
- The cast is not type-safe in all cases
- The function signature must be defined (again) for the cast
A type safe system would bring many benefits and help avoid nasty bugs.
We can make use of GCC extensions, but should provide a fallback (with
non-type-safety) for other compilers.

Possible approaches:
During the last years, we have investigated several option to address
this issue:

- Include headers with preprocessor magic.
This approach rewrites the "this" parameter for implementers by the
private variant (see [1] for details). But this approach has several
disadvantages: It requires much manual-to-maintain overhead in headers
and c files, a lot of work is required to port existing code, and it
does not allow to implement the same interface several times in the same
c file.

- Use public signature, manually cast "this" in function.
Casting the "this" parameter manually or with a macro is another option.
While it catches signature mismatches, it requires a public "this" for
the method signature and a private "this" for the implementation.
Explicit invocation of another macro is required to do the cast, making
the code more difficult to read and to maintain. Invoking such a
function from the same compilation unit will require to pass "this" as
public: another upcast.

- Use alias/weakref function implementing public signature.
Implementing the private signature and define a GCC weakref/alias with
the public signature would allow us to assign the public signature to
the interface without a cast. If a macro is used to define both
functions at once, parameter definition is required only once, and type
safety is guaranteed. However, the alias/weakref will be part of the
compiled output, and is not supported on all output
formats/architectures.

- this as transparent_union
Implementing the method with "this" as a transparent_union eliminates
the cast, as a function with a specified "this" is compatible to one
having "this" defined as transparent_union (assuming that the union
contains the same "this"). The problem with this approach is that "this"
in the method implementation must be accessed via the union (u.this),
rendering the code very unreadable.

- transparent_union with prototype declaration
Driving the approach above further can eliminate its problems: A
prototype declaration of the method with a "this" as transparent_union
of the public and private pointer, but defining the implementation with
the private "this" only will make GCC happy. This allows us to assign
the transparent_union declaration type to the public interface, as these
types are compatible. Wrapping the prototype and the implementation in a
single macro will make method declaration somewhat non standard-C, but
simple and intuitive. This, however, requires another quirk with a local
variable, as GCC would take the signature of the implementation instead
of the prototype, resulting in a type mismatch.

Status:
We have experimented with all the proposed solutions above, but the
approach with transparent_union and prototypes looks most promising. The
'nocast' branch contains the required macros in utils.h and some
migrated classes.

#define METHOD(iface, name, ret, this, ...) 	static ret name(union {iface *_public; this;} __attribute__((transparent_union)), ##__VA_ARGS__); 	const static typeof(name) *_##name = (const typeof(name)*)name; 	static ret name(this, ##__VA_ARGS__)

This macro defines a method signature for implementation, using a
prototype with a transparent union and an implementation using the
private "this" only. The local variable with the "_" prefix is assigned
to the interface, GCC will strip it out during optimization.

The following change is required to migrate the fetch() method of the
curl_fetcher_t implementation:

-/**
- * Implements fetcher_t.fetch.
- */
-static status_t fetch(private_curl_fetcher_t *this, char *uri, chunk_t *result)
+METHOD(fetcher_t, fetch, status_t,
+    private_curl_fetcher_t *this, char *uri, chunk_t *result)
 {

Read: fetcher_t.fetch returns status_t and takes
      private_curl_fetcher_t *this followed by other parameters.
We can omit the comment, as the METHOD macro already contains this
information in an always up-to-date form.

We further have introduced a INIT() macro for class instantiation, the
curl_fetcher_t constructor reads:

 private_curl_fetcher_t *this;

 INIT(this,
     .public.interface = {
         .fetch = _fetch,
         .set_option = _set_option,
         .destroy = _destroy,
     },
     .curl = curl_easy_init(),
 );
 [...]
The designated initializer guarantees that the memory is initialized to
zero; Any missed function pointer will result in a reproducible error.
0/NULL initializations are obsolete.


Migration:
We probably will include this macros in 4.3.6 and implement new classes
using them. If we don't run into problems, we can start migrating class
by class for the 4.4.0 release.

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多