95

I heard C11 added generics. I've googled a bit, looked at some articles, understood there's a new keyword ( _Generic ) and all. But I can't seem to grasp it all.

Is it something like the generics in C# or templates in C++? Can anyone give me a brief explanation of the C11 definition of generics, its syntax and a simple sample usage example?

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
ApprenticeHacker
  • 21,351
  • 27
  • 103
  • 153

3 Answers3

131

The best example I have seen inspired the following (runnable) example, which unlocks all sorts of freaky possibilities for cracked-out introspection...

#include <stdio.h>
#include <stddef.h>
#include <stdint.h>

#define typename(x) _Generic((x),        /* Get the name of a type */             \
                                                                                  \
        _Bool: "_Bool",                  unsigned char: "unsigned char",          \
         char: "char",                     signed char: "signed char",            \
    short int: "short int",         unsigned short int: "unsigned short int",     \
          int: "int",                     unsigned int: "unsigned int",           \
     long int: "long int",           unsigned long int: "unsigned long int",      \
long long int: "long long int", unsigned long long int: "unsigned long long int", \
        float: "float",                         double: "double",                 \
  long double: "long double",                   char *: "pointer to char",        \
       void *: "pointer to void",                int *: "pointer to int",         \
      default: "other")

#define fmt "%20s is '%s'\n"
int main() {

  size_t s; ptrdiff_t p; intmax_t i; int ai[3] = {0}; return printf( fmt fmt fmt fmt fmt fmt fmt fmt,

     "size_t", typename(s),               "ptrdiff_t", typename(p),     
   "intmax_t", typename(i),      "character constant", typename('0'),
 "0x7FFFFFFF", typename(0x7FFFFFFF),     "0xFFFFFFFF", typename(0xFFFFFFFF),
"0x7FFFFFFFU", typename(0x7FFFFFFFU),  "array of int", typename(ai));
}
                 ╔═══════════════╗ 
═════════════════╣ Amazeballs... ╠═════════════════════════════════════
                 ╚═══════════════╝ 
            size_t is 'unsigned long int'
         ptrdiff_t is 'long int'
          intmax_t is 'long int'
character constant is 'int'
        0x7FFFFFFF is 'int'
        0xFFFFFFFF is 'unsigned int'
       0x7FFFFFFFU is 'unsigned int'
      array of int is 'other'
Alex Gray
  • 16,007
  • 9
  • 96
  • 118
  • 1
    wow. what compiler do you use? on my machine (Linux, GCC 4.9+), the latest type is shown as "pointer to int': array of int is 'pointer to int' – user1284631 Mar 26 '15 at 15:52
  • > Apple LLVM version 6.1.0 (clang-602.0.45) (based on LLVM 3.6.0svn) – Alex Gray Mar 27 '15 at 02:06
  • 15
    This is neat, but you can never cover all types this way... anyway, +1 for "Amazeballs"... – einpoklum Nov 18 '15 at 10:09
  • 3
    Actually, @einpoklum, you can cover all non-composite types this way... there are five integer types and their unsigned counterparts, and 3 floating-point types and their complex counterparts for a total of 16 basic types. When you include storage classes (normal, `const`, `volatile`, and `volatile const`) that gives you 64 distinct variations. Cumbersome, but not impossible. Pointers to each of these types doubles that number, and pointers-to-pointers increases it further... but that gives 192 variations in total... ugh! But stil not impossible. – SGeorgiades Feb 26 '21 at 18:02
  • 1
    @SGeorgiades: But you want typename() to work for composite types as well. – einpoklum Feb 26 '21 at 18:43
  • @einpoklum: I can use `_Generic` to determine `struct` types. Is that what you mean by composite types? Is this just a clang extension that I'm unknowingly using? – SO_fix_the_vote_sorting_bug May 18 '21 at 19:09
  • @jdk1.0: You can't use these definitions to get the type of an arbitrary struct. Also, not of arrays (ignoring decay here), or of unions. or enums. I think that covers it. – einpoklum Jun 30 '21 at 12:59
  • @SO_fix_the_vote_sorting_bug about your last question `_Generic` is part of C11 standard not compiler extension and yes you can use `_Generic` to check struct types – Blanket Fox Dec 18 '22 at 04:41
63

This is a pretty good introduction. Here's the Overview:

Generic selection is implemented with a new keyword: _Generic. The syntax is similar to a simple switch statement for types:_Generic( 'a', char: 1, int: 2, long: 3, default: 0) evaluates to 2 (character constants are ints in C).

Basically it works like a kind of switch, where the labels are type names which are tested against the type of the first expression (the 'a' above). The result becomes the result of evaluating the _Generic().

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
unwind
  • 391,730
  • 64
  • 469
  • 606
  • 1
    Just realized I linked to the same page as you had.. No wonder, though.. It’s really the only good spot for any info on this stuff, oddly... – Alex Gray Jun 25 '13 at 06:23
5

I use CLion 1.2.4, and CLion doesn't support C11 now, so I use following code in GNU C99 instead of _Generic

#include <stdio.h>

int main(int argc, char **argv) {
    char *s;
    if (__builtin_types_compatible_p(__typeof__(s), long)) {
        puts("long");
    } else if (__builtin_types_compatible_p(__typeof__(s), char*)) {
        puts("str");
    }
    return (0);
};
Blanket Fox
  • 377
  • 4
  • 15
izhkymonte
  • 185
  • 1
  • 1
  • 33
    How does "here's what I use instead of _Generic" have 8 upvotes on a question asking for an example of how to use _Generic – Michael Mrozek Jan 05 '19 at 06:59
  • 17
    @MichaelMrozek - This answer provides an alternative approach, which if nothing else, is illustrative of the _concept being asked about_. One characteristic of an alternative approach to _anything_ is that it will always provide a new and unique perspective on _the thing being asked about_. Teachers use this technique all the time. If you stand in one spot and stare at something and yet do not understand it, walk around and look at it from another perspective. This always provides new information. That, whether intended or not, is one thing this answer provides. (+1 for that) – ryyker May 15 '19 at 12:38
  • 13
    This is GNU C, not C99 – osvein May 31 '20 at 16:48