Live data from Hacker News

Learning that you can use unions in C for grouping things into namespaces

utcc.utoronto.ca

41–50 of 150 posts

Re: Learning that you can use unions in C for grouping things into namespaces

#41

Anonymous nested structs are also quite useful for creating struct fields with explicit offsets: #include #include #define YDUMMY(suffix, size) char dummy##suffix[size] #define XDUMMY(suffix, size) YDUMMY(suffix, size) #define PAD(size) XDUMMY(__COUNTER__, size) struct ExplicitLayoutStruct { union { struct __attribute__((packed)) { PAD(3); uint32_t foo; }; struct __attribute__((packed)) { PAD(5); uint16_t bar; }; str…

Anytime macros are used for metaprogramming, it's time to reach for a more powerful language.

Macros are useful, as long as they're used sparingly. I think that in this case, it's used well - the struct is still perfectly readable, and the sole purpose of it is to make it so that you don't have to manually name the dummy fields. But you could totally just write out dummy1, dummy2, dummy3 etc. yourself if you want to get rid of the macros.

Re: Learning that you can use unions in C for grouping things into namespaces

#42
post #33

Earlier quoted context omitted.

Yes, I was looking to demonstrate the flexibility of the approach by including overlapping fields.

If you write to either, accessing the other, even on the overlap, is undefined behaviour

Type punning/aliasing with unions is well defined in gcc. Linus even has a humorous rant about it on the topic:

https://www.yodaiken.com/2018/06/07/torvalds-on-aliasing/

Sure, it's compiler-specific, but I'm already using `__attribute__((packed))` anyways.

Re: Learning that you can use unions in C for grouping things into namespaces

#43
post #31

Anonymous nested structs are also quite useful for creating struct fields with explicit offsets: #include #include #define YDUMMY(suffix, size) char dummy##suffix[size] #define XDUMMY(suffix, size) YDUMMY(suffix, size) #define PAD(size) XDUMMY(__COUNTER__, size) struct ExplicitLayoutStruct { union { struct __attribute__((packed)) { PAD(3); uint32_t foo; }; struct __attribute__((packed)) { PAD(5); uint16_t bar; }; str…

There are two kinds of undefined behaviour being invoked in using this. Its a horrible idea and a horrible code smell, get rid of it if you ever see something like this.

I don't see any undefined behavior here. As I mentioned below, gcc explicitly documents type punning via unions as being well defined. But yes, this is compiler specific and is not guaranteed to work elsewhere.

Re: Learning that you can use unions in C for grouping things into namespaces

#44
post #32
post #18

Earlier quoted context omitted.

One of the very few things from C that I miss in C++ is anonymous structs and enums. I really don’t understand why they are not allowed. That is, C style enums don’t have to have a name but “type safe” (enum class) ones do. One classic use is to name an otherwise boolean option in a function signature; there’s typically no need to otherwise name it. C++ incompatibly requires a name for all struct and class declaratio…

Use a enum in a namespace, or anonymous namespace

This is an example of the desired use case:

    static obj& some_call (obj& o, enum struct { abandon, save } disposition) { ... };
This is a common case (and should be more common) to avoid using an obscure boolean flag, which can lead to bugs. It shouldn't need a name.

An anonymous namespace just means the name itself won't leak out; under C++ rules I need the name even to specify the enum tag, which is absurd.

Re: Learning that you can use unions in C for grouping things into namespaces

#45

Anonymous nested structs are also quite useful for creating struct fields with explicit offsets: #include #include #define YDUMMY(suffix, size) char dummy##suffix[size] #define XDUMMY(suffix, size) YDUMMY(suffix, size) #define PAD(size) XDUMMY(__COUNTER__, size) struct ExplicitLayoutStruct { union { struct __attribute__((packed)) { PAD(3); uint32_t foo; }; struct __attribute__((packed)) { PAD(5); uint16_t bar; }; str…

Anytime macros are used for metaprogramming, it's time to reach for a more powerful language.

Doesn’t work in a lot of cases unfortunately. If you’re writing a library designed to be consumed by other languages you’re stuck with writing C abi compatible code which can be written in other languages that can “extern” them but it puts limits on what’s possible in those libraries.

Re: Learning that you can use unions in C for grouping things into namespaces

#46
post #30

This is probably a terrible idea, remember that if you have written one member of a union, all other members remain public, yet accessing any of them in any way is undefined behaviour. This is made way worse by most compilers mostly choosing to let you do what you think it will. They just dont guarantee they always will or in all cases.

I believe you are mistaken. The C11 standard, section 6.5.2.3 "Structure and union members" pgf 6, says "One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members." And that seems to be what's being used here.

Re: Learning that you can use unions in C for grouping things into namespaces

#47
post #33

Earlier quoted context omitted.

If you write to either, accessing the other, even on the overlap, is undefined behaviour

Type punning/aliasing with unions is well defined in gcc. Linus even has a humorous rant about it on the topic: https://www.yodaiken.com/2018/06/07/torvalds-on-aliasing/ Sure, it's compiler-specific, but I'm already using `__attribute__((packed))` anyways.

All undefined behaviour is well defined for each compiler, what it really means is implementation defined and subject to change without notice or documentation with every compiler version or host os what flags are enabled or a thousand other things. Why use an approach which strictly relies on specific versions of specific compilers, rather than a completely portable and standard compliant struct with char array and a few char pointers? Or if you want a convenient interface and aren't explicitly writing for the kernel, switch to a restricted subset of C++ and do it right?

Re: Learning that you can use unions in C for grouping things into namespaces

#48
post #46
post #30

This is probably a terrible idea, remember that if you have written one member of a union, all other members remain public, yet accessing any of them in any way is undefined behaviour. This is made way worse by most compilers mostly choosing to let you do what you think it will. They just dont guarantee they always will or in all cases.

I believe you are mistaken. The C11 standard, section 6.5.2.3 "Structure and union members" pgf 6, says "One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declar…

No: from https://en.cppreference.com/w/cpp/language/union.

The union is only as big as necessary to hold its largest data member. The other data members are allocated in the same bytes as part of that largest member. The details of that allocation are implementation-defined but all non-static data members will have the same address (since C++14). It's undefined behavior to read from the member of the union that wasn't most recently written. Many compilers implement, as a non-standard language extension, the ability to read inactive members of a union.

What 6.5.2.3 simplifies is the use of unions of the type:

struct A{int type; DataA a;}

struct B{int type; DataB b;}

union U{A a;B b};

U u;

switch(u.type)...

Its not what is beeing used here.

std::variant is designed to deprecate all legitimate uses of union

Re: Learning that you can use unions in C for grouping things into namespaces

#49
post #38

I don't regard this as a "perverse" hack. If I ever do embedded memory mapped stuff in C11 this is way too tempting.

You are practically guaranteed to invoke undefined behaviour if you do. Just use a map on a std::array of e.g. std::byte

they said C11 tho

Re: Learning that you can use unions in C for grouping things into namespaces

#50
post #31

Earlier quoted context omitted.

There are two kinds of undefined behaviour being invoked in using this. Its a horrible idea and a horrible code smell, get rid of it if you ever see something like this.

I don't see any undefined behavior here. As I mentioned below, gcc explicitly documents type punning via unions as being well defined. But yes, this is compiler specific and is not guaranteed to work elsewhere.

There is absolutely undefined behaviour there. Undefined behaviour is defined not as nasal daemons but as: The compiler implementer does not guarantee that this behaviour will be hardware, circumstance, compiler version, or os consistent, nor that we will warn if we change this.

Packed is technically not a undefined behaviour, but it is certainly a trap. Especially because the compiler macros leads people to make defines which select packed by compiler automatically. Then the special case of didn't recognize compiler is just left empty, meaning compiles but no longer does what you think.

Post reply on HN