Live data from Hacker News

Workarounds for C11 _Generic()

chiark.greenend.org.uk

21–30 of 58 posts

Re: Workarounds for C11 _Generic()

#21

The only reason I can imagine for this behaviour is that the compiler/standard writers did not want it. Maybe C just shouldn't include generics. Especially not as part of the macro layer.

The macros in tgmath and more recently stdbit show why those could be necessary. If you have a set of functions for addition with overflow detection, say add_overflow{i,l,ll}, and you have a pair of ptrdiff_t’s or int32_t’s or whatnot that you know are standard integer types, and you want to use the appropriate add_overflow* function, can you do it? With _Generic you can. Without it I think you’re stuck providing sep…

You make it sound alot more complicated. Ignoring the library functions or stuff you can include from safe coding standard headers. You just do something like.

  BOOL AddOverflowUnsigned(BYTE* a, BYTE* b, INT32 sizea, INT32 sizeb)
  {
     BOOL IsMsb = PlatformIsMSB();
     BOOL IsLsb = PlatformIsLSB();
     
     //log error
     if(!IsMsb && !IsLsb)
       return FALSE;

     //Early out for overflow. Assuming 
     if(sizea == sizeb && PlatformIsMSB())
     {
        BOOL AMsb = (a >> ((sizea * PlatformByteSize()) - 1)) & 1;
        BOOL BMsb = (b >> ((sizeb * PlatformByteSize()) - 1)) & 1;
        if(AMSB && BMsb)
        {
           //We overflow, early out.
           return FALSE;
        }
      else if(sizea == sizeb && PlatformIsLSB())
        //Code here.

     //We add using bitwise operators so we can do it on any size.
     //SUM = A XOR B XOR CARRY, return in A
     //Impliment algo here.

     return TRUE;
  }

  int main()
  {
     UINT64 a = 69;
     UINT64 b = 420;
     if(sizeof(a) !
     return AddOverflowUnsinged(&a, &b, sizeof(a), sizeof(b));
  }

But they have this in the STD now and also all the secure coding libs have this in it's header as a basic function. There's also the easier implementation of just adding a check to see if it will overflow, rather than add in the function.

You also only have a few you can hardcode if you don't do it generic, since all will go back to the primitives of uint8, uint16 ....

Re: Workarounds for C11 _Generic()

#22
Tiny C compiler actually has a "bug" in not implementing the "big bug".

That is, the following expressions are cleanly compiled without any errors:

    _Generic(0, float: s/]*>/ /g, int: 1),
    _Generic(0, float: now the thing about this tcc implementaion is, int: 1),
    _Generic(0, float: that it just skips until the next comma, int: 1),
    _Generic(0, float: keeping track of parentheses nesting., int: 1),
    _Generic(0, float: [[ Suprizingly it doesnt validate which parentheses)), int: 1),
    _Generic(0, float:  {{{so this bullshit is possible))), int: 1,
             default: #else #define this is great isnt it?);
See: https://godbolt.org/z/o7jne7hWM

Re: Workarounds for C11 _Generic()

#23
post #6

Will this work? define string_length(x) _Generic(x, \ const char * : strlen((const char*)(const void*)x), \ struct MyStringBuffer * : ((const MyStringBuffer*)(const void*)x)->length)

Heh, this was my first thought as well, and it does indeed compile and work (with GCC 12.2, anyway).

Yeah, this is what I saw in some example code. Also you don't need the (void*), at least not with clang or GCC trunk on compiler explorer: https://godbolt.org/z/a8rP91dKr

Re: Workarounds for C11 _Generic()

#24

The only reason I can imagine for this behaviour is that the compiler/standard writers did not want it. Maybe C just shouldn't include generics. Especially not as part of the macro layer.

This is bad for non-compiler tools.

Without it, we can parse the preprocessed source code.

With the enhancement proposed, we need to do half the compiler's work.

In tools like IDE, we want quick (sub millisecond) feedback for most edits

Re: Workarounds for C11 _Generic()

#25
post #6

Will this work? define string_length(x) _Generic(x, \ const char * : strlen((const char*)(const void*)x), \ struct MyStringBuffer * : ((const MyStringBuffer*)(const void*)x)->length)

Heh, this was my first thought as well, and it does indeed compile and work (with GCC 12.2, anyway).

[deleted]

Re: Workarounds for C11 _Generic()

#26

Earlier quoted context omitted.

Just use C++ with just templates?

That would be my advice too. What was the point of “You don’t pay for what you don’t use” if nobody’s going to use it?

There's no common C++ build system. That means (among other things) that there's no way to turn features you don't use into compile-time errors. There's no project configuration to select an allowed subset of features. All the difficulty goes onto the programmers, and in a multi-person project into the code review process. In practice, you end up using the combined set of C++ sublanguages each contributor chooses to use. You have to know about all of C++'s features to use C++ in a large enough team.

Re: Workarounds for C11 _Generic()

#27

The only reason I can imagine for this behaviour is that the compiler/standard writers did not want it. Maybe C just shouldn't include generics. Especially not as part of the macro layer.

Generics are fine. Its useful to have some introspection into the data that compiler has. Thats the whole point of macros in the first place.

The behavior with _Generic is basically emergent behavior from implementation of macro processors. Macro replacements occur prior to actual compilation, so no compiler context exists for x, as such all code paths must be valid.

Its much easier to require the programmer typecast x in the replacement value then start trying to shoehorn the compiler context into macro processors.

Re: Workarounds for C11 _Generic()

#28
It sounds like the author misunderstands the purpose of _Generic. The author wants it to behave like pattern matching in ML languages, but that is not its purpose. The purpose of generic selection was to introduce function overloading [1] into C without breaking ABI compatibility.

[1] https://en.wikipedia.org/wiki/Ad_hoc_polymorphism

Re: Workarounds for C11 _Generic()

#29
I would have designed the feature like this:

  _Generic(, type1 : ( expr1 ), type2 : ( expr2 ), ... default : ( expr ))
Here, the parentheses shown in this phrase pattern are required.

The implementation would only parse and semantically analyze the expression of the matching type. For the others, the ( expr ) would be treated as a token sequence to be skipped, which has to contain valid tokens, and balancing parentheses, square brackets and braces.

E.g.

   char *p = "foo"

   _Generic(p : int : ("foo" ++ / ? ([]&xyz) { ; } ),
                char * : (p[0]))

Here, the type of p doesn't match int, and so the interior token sequence of ("foo" ++ / ? ([]&xyz) { ; } ) would just be scanned to check for balancing parentheses, brackets and braces, which allows the parser to locate the next clause in the association list.

Re: Workarounds for C11 _Generic()

#30
post #28

It sounds like the author misunderstands the purpose of _Generic. The author wants it to behave like pattern matching in ML languages, but that is not its purpose. The purpose of generic selection was to introduce function overloading [1] into C without breaking ABI compatibility. [1] https://en.wikipedia.org/wiki/Ad_hoc_polymorphism

[deleted]
Post reply on HN