• GCC C语言特性


    GCC C特性
    在C语言的编程过程中,适当使用gcc的C语言特性,可以提高我们的编程效率,代码也更整洁,更清晰。
    比如语句表达式,可以把一块语句当作一个表达式,返回最后的语句,个人常使用于宏的定义,感觉比用do{ }while(0)表示一块语句更直观,而且定义的宏还能当作表达式赋值给变量。
    还有定义局部变量时,加上__cleanup__属性,当局部变量退出作用域时会自动调用指定cleanup函数,这样一来,我们可以对内存指针添加释放内存函数,让它自动调用free释放内存,当一个函数内,存在多处返回时不需要多处调用free,对多线程加锁场景,巧妙使用__cleanup__特性,也可以让锁自动进行解锁操作,不用担心忘记解锁而导致死锁。对__cleanup__特性的使用,glib库中定义的g_auto和g_autoptr宏就应用得很不错,值得学习。
    GCC C扩展特性有很多,以下是个人觉得非常值得学习和使用的特性。

    1、语句表达式

    //表达式为一块语句,最后的为返回值,类似逗号表达式
    ({ int y = foo (); int z;
       if (y > 0) z = y;
       else z = - y;
       z; })
    
    #define foreach(v) \
       for(int i = 0; ({printf("i[%d] < v[%d]\n", i, v); i < v;}); ({printf("i = %d\n", i);     i++;}))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    2、本地声明的标签

    #define SEARCH(value, array, target)              \
    do {                                              \
      __label__ found;                                \
      typeof (target) _SEARCH_target = (target);      \
      typeof (*(array)) *_SEARCH_array = (array);     \
      int i, j;                                       \
      int value;                                      \
      for (i = 0; i < max; i++)                       \
        for (j = 0; j < max; j++)                     \
          if (_SEARCH_array[i][j] == _SEARCH_target)  \
            { (value) = i; goto found; }              \
      (value) = -1;                                   \
     found:;                                          \
    } while (0)
    
    //普通标签不能在宏里使用,本地声明的标签可以
    //使用语句表达式返回value
    #define SEARCH(array, target)                     \
    ({                                                \
      __label__ found;                                \
      typeof (target) _SEARCH_target = (target);      \
      typeof (*(array)) *_SEARCH_array = (array);     \
      int i, j;                                       \
      int value;                                      \
      for (i = 0; i < max; i++)                       \
        for (j = 0; j < max; j++)                     \
          if (_SEARCH_array[i][j] == _SEARCH_target)  \
            { value = i; goto found; }                \
      value = -1;                                     \
     found:                                           \
      value;                                          \
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    3、标签作为值

    //不建议使用
    void *ptr;
    /* … */
    ptr = &&foo;
    goto *ptr;
    
    static void *array[] = { &&foo, &&bar, &&hack };
    goto *array[i];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4、嵌套函数

    //只能用于 C ,不能用于 C++
    hack (int *array, int size)
    {
      void store (int index, int value)
        { array[index] = value; }
    
      intermediate (store, size);
    }
    
    //嵌套函数与本地标签一起使用
    bar (int *array, int offset, int size)
    {
      __label__ failure;
      int access (int *array, int index)
        {
          if (index > size)
            goto failure;
          return array[index + offset];
        }
      int i;
      /* … */
      for (i = 0; i < size; i++)
        /* … */ access (array, i) /* … */
      /* … */
      return 0;
    
     /* Control comes here from access
        if it detects an error.  */
     failure:
      return -1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    5、非本地跳转

    6、__builtin_函数调用

    extern int myprintf (FILE *f, const char *format, ...);
    extern inline __attribute__ ((__gnu_inline__)) int
    myprintf (FILE *f, const char *format, ...)
    {
      int r = fprintf (f, "myprintf: ");
      if (r < 0)
        return r;
      int s = fprintf (f, format, __builtin_va_arg_pack ()); //可变参数调用,不使用宏
      if (s < 0)
        return s;
      return r + s;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    7、typeof or typeof

    //可以和语句表达式一起使用
    #define max(a,b) \
      ({ typeof (a) _a = (a); \
          typeof (b) _b = (b); \
        _a > _b ? _a : _b; })
        
    typeof (*x) y;
    typeof (typeof (char *)[4]) y;  //char *y[4];
    
    #define pointer(T)  typeof(T *)
    #define array(T, N) typeof(T [N])
    
    //__auto_type 类似于 C++ 中的 auto
    #define max(a,b) \
      ({ __auto_type _a = (a); \    //优先使用__auto_type,而不是typeof
          __auto_type _b = (b); \
        _a > _b ? _a : _b; })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    8、条件表达式(省略操作数)

    x ? : y
    
    • 1

    9、128位整型

    __int128
    unsigned __int128
    
    • 1
    • 2

    19、空结构体

    struct empty {
    };    //空结构体,占用字节数为 0
    
    • 1
    • 2

    20、可变长度数组

    FILE *
    concat_fopen (char *s1, char *s2, char *mode)
    {
      char str[strlen (s1) + strlen (s2) + 1];    //数组长度不是常量表达式,长度可变
      strcpy (str, s1);
      strcat (str, s2);
      return fopen (str, mode);
    }
    
    void
    foo (int n)
    {
      struct S { int x[n]; };    //结构体中包含可变长度数组
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    27、非常量初始值

    foo (float f, float g)
    {
      float beat_freqs[2] = { f-g, f+g };
      /* … */
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    30、case 范围

    switch(i)
    {
        case low ... high:
            /* ... */
        case 1 ... 5:
            /* ... */
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    33、通用函数属性

    constructor 构造函数属性
    destructor 析构函数属性

    34、变量__cleanup__属性

    #include                                                                            
    #include 
    #include 
    
    void free_str(char **str)
    {
        printf("free %p\n", *str);
        free(*str);
    }
    
    //设置变量退出作用域自定调用函数释放内存
    #define FREE_STR __attribute__ ((__cleanup__(free_str)))
    
    #define Str FREE_STR char
    
    
    int main()
    {
        Str *p = malloc(100);
        strcpy(p, "test for auto free.");
        printf("%s\n", p);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
  • 相关阅读:
    如何在React中监听键盘事件
    Redis高级数据结构HyperLogLog
    实现一个函数,判断aim是 否是str1和str2交错组成。
    如何搭建属于自己的查题公众号?
    【C++】泛型编程
    c# 基础习题答案 20240709
    Jetpack Compose 和 SwiftUI 与 Flutter 的比较
    专业制造一体化ERP系统,专注于制造工厂生产管理信息化,可定制-亿发
    CANoe新建XML自动化Test Modules
    uniapp 打包后各静态资源加载失败的问题(背景图,字体等)
  • 原文地址:https://blog.csdn.net/lslin405/article/details/126563605