【问题标题】:Syntax and Sample Usage of _Generic in C11C11中_Generic的语法和示例用法
【发布时间】:2012-03-21 12:11:34
【问题描述】:

我听说 C11 添加了泛型。我用谷歌搜索了一下,看了一些文章,了解到有一个新关键字(_Generic)等等。但我似乎无法全部掌握。

它是像 C# 中的泛型还是 C++ 中的模板?谁能给我简要解释一下泛型的 C11 定义、它的语法和一个简单的示例用法示例?

【问题讨论】:

  • 您可以阅读或下载draft of the C11 Standard(PDF 版本)。它在第 6.5.1.1 节中有一个示例。
  • C++ 中没有“泛型”之类的东西。
  • @Griwes 给你。还要吹毛求疵吗?

标签: c generics c11


【解决方案1】:

The best example I have seen 启发了以下(可运行的)示例,它为破解内省提供了各种奇怪的可能性......

#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'

【讨论】:

  • 哇。你用什么编译器?在我的机器(Linux,GCC 4.9+)上,最新的类型显示为“pointer to int”:array of int is 'pointer to int'
  • > Apple LLVM 版本 6.1.0 (clang-602.0.45)(基于 LLVM 3.6.0svn)
  • 这很简洁,但您永远无法以这种方式涵盖所有类型...无论如何,为“Amazeballs”+1...
  • 实际上,@einpoklum,您可以通过这种方式涵盖所有非复合类型...共有五种整数类型及其无符号对应物,以及 3 种浮点类型及其复杂对应物,总共16 种基本类型。当您包含存储类(普通、constvolatilevolatile const)时,会为您提供 64 种不同的变体。麻烦,但并非不可能。指向这些类型中的每一种的指针都会使该数字翻倍,而指向指针的指针会进一步增加它……但这总共有 192 种变体……呃!但也不是不可能。
  • @SGeorgiades:但是您希望 typename() 也适用于复合类型。
【解决方案2】:

This 是一个很好的介绍。这是概述:

使用新关键字实现通用选择:_Generic。语法类似于 类型的简单 switch 语句:_Generic( 'a', char: 1, int: 2, long: 3, default: 0) 计算结果为 2(字符常量在 C 中是整数)。

基本上它的工作方式类似于switch,其中标签是针对第一个表达式的类型进行测试的类型名称(上面的'a')。结果成为评估_Generic()的结果。

【讨论】:

  • 刚刚意识到我链接到的页面与您链接的页面相同。不过也难怪.. 奇怪的是,这确实是获取任何有关这些信息的唯一好地方...
【解决方案3】:

我用的是clion 1.2.4,现在clion不支持c11,所以我在c99中用下面的代码代替_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);
};

【讨论】:

  • “这是我使用的,而不是 _Generic”如何在询问如何使用 _Generic 示例的问题上获得 8 票赞成
  • @MichaelMrozek - 这个答案提供了一种替代方法,如果没有别的,它说明了被询问的概念anything 的另一种方法的一个特点是,它总是为 被询问的事物 提供一个新的和独特的视角。老师们一直在使用这种技术。如果你站在一个地方盯着某个东西看,但不理解它,那就四处走走,从另一个角度看它。这总是提供新的信息。无论是否有意,这是这个答案提供的一件事。 (为此+1)
  • 这是 GNU C,不是 C99
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多