Live data from Hacker News

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

utcc.utoronto.ca

81–90 of 150 posts

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

#81
post #61

Earlier quoted context omitted.

> I really don’t understand why they are not allowed. I don't, either. Such were in D from 2000 or so. I also don't understand why `class` in C++ sits in the tag name space. I wrote Bjarne in the 1980s asking him to remove it from the tag name space, as the tag name space is an abomination. He replied that there was too much water under that bridge. D doesn't have the tag name space, and in 20 years not a single pers…

The only explanation I saw was that C++ standards guys were horrified by the idea of unpredictable side effects as a result of initialization of a struct. I think C++ though is adding them. What I'd like in c is designated function parameters. // these the same bar(.a = 10, .b = 12); bar(.b = 12, .a = 10);

You can somewhat fake it by replacing your functions parameters list with a single struct parameter.

    struct bar_arguments {
       int a, b;
    };
    int bar(struct bar_arguments args) { return 2*args.a + args.b;}

    #define bar(...) bar((struct bar_arguments) {__VA_ARGS__})

    // usage (will print 32 three times)
    printf("%d\n", bar(10, 12));
    printf("%d\n", bar(.a = 10, .b = 12));
    printf("%d\n", bar(.b = 12, .a = 10));

The main drawback is that all parameters are now optional: it will not complain if you forget to assign all parameters, it will silently set them to 0 :-/

    printf("%d\n", bar(10));
    printf("%d\n", bar(.a = 10));
    printf("%d\n", bar(.b = 12));
will print 20, 20 and 12.

You can change those "default values", but then calling the function with regular positional parameters is impaired :-/

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

#82
post #48
post #46

Earlier quoted context omitted.

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…

You've mentioned this several times on this page, but this is still incorrect.

The C standard references "struct or union" all over the place because the two are so similar. The distinction is of course made clear in multiple places, but one that seems relevant here is:

> As discussed in 6.2.5, a structure is a type consisting of a sequence of members, whose storage is allocated in an ordered sequence, and a union is a type consisting of a sequence of members whose storage overlap. (ISO/IEC 9899:201x, §6.7.2.1, #6)

That's it. There's nothing about undefined behavior if you access one member and then another later. In fact there's even a paragraph which mentions doing just that:

> The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bitfield, then to the unit in which it resides), and vice versa. (ISO/IEC 9899:201x, §6.7.2.1, #16)

A pointer to the union points to each of its members, and can be dereferenced to access it.

std::variant is not used in C; C and C++ are two different languages.

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

#83
post #35

Earlier quoted context omitted.

This is also known as the most common invocation of undefined behaviour in game programming. If you do this, write to y, then read from [1]. You are invoking undefined behaviour, and compilers doing different things here between windows, linux mac, and different compiler versions is a common cause of "why isnt my game working right on XXX, it works fine on YYY questions.

I don’t see the undefined behavior here?

Op probably means cpp, where it is indeed undefined behavior. not sure about c. I doubt that if this would cause a "my game does not work on XXX" though. Is there really a compiler out there that will handle such abuse differently?

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

#84

Earlier quoted context omitted.

You might as well have written that "any time you're reaching for C, it's time to reach for a more powerful language". But if -sadly- you must use C, metaprogramming using macros is not a terrible thing.

> is not a terrible thing It is a terrible thing. It's possible to do without them, and you'll like your code better. Your symbolic debugger and syntax directed editor will work properly. The poor schlub who has to fix the bugs in your code after you leave will be grateful. Your spouse will be happy and your children will prosper. For example, #define foo(x) ((x) + 1) replace with: int foo(int x) { return x + 1; } Th…

   The optimizer will delete bar() if FOO is a manifest constant that is not 3. 
Yes, but the compiler won't delete it and complain if bar is not defined. if constexpr is not a direct replacement for if macro

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

#85

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…

IMO you can still be explicit about field offsets by writing the struct in a usual way, and using static assertions to ensure offsets match the intended layout.

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

#86

Earlier quoted context omitted.

Linux kernel is large project and clearly C is sufficient for it, given the fact that migrating to C++ would probably be very easy (not using all C++ features, but just selected ones), yet it did not happen. I think that C++ is better than C, but C is not that bad, even for large projects.

And the Kernel devs would probably get really annoyed if you try to push this kind of name-spacing. > C++ would probably be very easy Not necessary, besides some small? problems due to the C++ allowing "more magic optimizations" then C they would switch to a sub-set of C++, and it might be so you would need to communicate to all contributors that a lot of C++ things are not allowed. And it might be easier to simple n…

> And the Kernel devs would probably get really annoyed if you try to push this kind of name-spacing.

Actually, they use it themselves. [0]

[0] https://lwn.net/SubscriberLink/864521/d704bdcced0c5c60/

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

#87

Earlier quoted context omitted.

You might as well have written that "any time you're reaching for C, it's time to reach for a more powerful language". But if -sadly- you must use C, metaprogramming using macros is not a terrible thing.

> is not a terrible thing It is a terrible thing. It's possible to do without them, and you'll like your code better. Your symbolic debugger and syntax directed editor will work properly. The poor schlub who has to fix the bugs in your code after you leave will be grateful. Your spouse will be happy and your children will prosper. For example, #define foo(x) ((x) + 1) replace with: int foo(int x) { return x + 1; } Th…

Having made a significant contribution to Simon Tatham's PuTTY, I have to respectfully disagree. At the time the entire SSHv2 key exchange and user authentication protocols were implemented in a single function using a massive Duff's device (for asynchrony) implemented with C metaprogramming macros. It was a surprisingly pleasant experience.

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

#88
post #35

Imo this is not “perverse”. In my vector library I alias a vec3 as float x,y,z and float[3] using this technique.

This is also known as the most common invocation of undefined behaviour in game programming. If you do this, write to y, then read from [1]. You are invoking undefined behaviour, and compilers doing different things here between windows, linux mac, and different compiler versions is a common cause of "why isnt my game working right on XXX, it works fine on YYY questions.

Type punning is not undefined, it's implementation defined in C. In practice, every major C compiler will be fine with type punning, though it may disable some optimizations.

The story is different in C++, but in practice many compilers support it the same as in C. Especially for games, where VC++ (PC, Xbox) and Clang (PS4/PS5) are the most commonly used compilers, it also works as expected. The trick is to only use type punning for trivial structs that don't invoke complications like con/de-structors or operators. The GP's example of a Vec3 struct that puns float x,y,z with float[3] is a very common one in games.

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

#89
post #67
post #47

Earlier quoted context omitted.

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…

GCC explicitly states znd documents that type punning through unions will work as expected. This doesn't work by accident. It works very explicitly by design of GCC. Different GCC versions aren't randomly going to change documented behavior. And when they accidentally do, they will consider it a bug.

Regardless, type punning though a union is not undefined behavior in C the first place [1] [2]. On the other hand, it is undefined in C++, but GCC allows it there too.

[1] https://stackoverflow.com/questions/11639947/is-type-punning...

[2] https://stackoverflow.com/questions/25664848/unions-and-type...

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

#90
post #40

Earlier quoted context omitted.

Yeah they should have upgraded to some restricted subset of C++ or new restrictive language ages ago. I mostly buy the arguments against having exceptions, perhaps even against polymorphism in general, but the argument against destructors, or atomics... hell no.

> ...against polymorphism... C has polymorphism. Inheritance-based virtual dispatch is just one kind of polymorphism. It's common to wire up polymorphism in C with bespoke data structures using tagged unions it function pointers. Changing an implementation at link time is even a form of polymorphism.

> Changing an implementation at link time is even a form of polymorphism.

I never truly appreciated how polymorphism can take so many different forms!

Post reply on HN