Skip to content

240905-C语言语法特性

1 复合字面量

复合字面量(Compound Literals)是 C99 标准引入的一个特性,它允许你在表达式中创建一个数组或结构体,并且可以立即使用。复合字面量的语法是:(type){ initializer-list }

举例来说,如下之前新写的函数:

debug_print_array("My Array", UINT8, (Data){.uint8=5}, UINT8_ARRAY, (Data){.uint8_array=(uint8_t[]){1, 2, 3, 4, 5}}, 0, 5);

对于 (Data){.uint8=5} 以及 (Data){.uint8_array=(uint8_t[]){1, 2, 3, 4, 5}} 就使用了复合字面量的特性,在调用 debug_print_array 的形参表达式中创建了 Data 结构体,并立即初始化。

另外,复合字面量的生命周期和其所在的作用域保持一致。

复合字面量(Compound Literals)这个名字来自于它的构成。在 C 语言中,"复合"(Compound)通常指的是由多个部分组成的数据类型,例如结构体(Structures)和数组(Arrays)。"字面量"(Literals)则是源代码中表示值的固定表示法,例如 123 是一个整数字面量,"hello" 是一个字符串字面量。

因此,"复合字面量"就是一个由多个部分组成的字面量,它可以是一个结构体字面量,也可以是一个数组字面量。例如,(struct {int x; int y;}){1, 2} 是一个结构体字面量,(int[]){1, 2, 3} 是一个数组字面量。这些都是复合字面量的例子。

2 泛型选择器

在 C11 标准中,_Generic() 是一个关键字,它被引入作为一种类型安全的编译时选择机制。它允许程序员基于表达式的类型来选择不同的函数或代码块执行。这在处理多种数据类型时非常有用,可以减少代码的重复,并提高代码的可维护性。

2.1 语法

_Generic() 选择器的基本语法如下:

_Generic((expr), type1: val1, type2: val2, ..., default: val_default)
  • expr 是要检查类型的表达式。
  • type1, type2, ... 是 expr 可能的类型。
  • val1, val2, ... 是当 expr 分别匹配 type1, type2, ... 时返回的值或执行的代码块。
  • default 是当 expr 不匹配任何指定类型时的默认返回值或执行的代码块。

2.2 示例

假设我们有一个函数,它根据输入的类型返回不同的值:

#include <stdio.h>

#define SQUARE(x) _Generic((x), \
        default: (x * x), \
        int: (x * x), \
        char: (x * x), \
        float: (x * x), \
        double: (x * x))

int main() {
    int i = 5;
    char c = 'a';
    double d = 3.14;

    printf("Square of %d is %d\n", i, SQUARE(i));
    printf("Square of '%c' is %d\n", c, SQUARE(c));
    printf("Square of %f is %f\n", d, SQUARE(d));

    return 0;
}

在这个例子中,SQUARE 宏使用 _Generic() 来根据参数的类型选择不同的代码块。由于所有类型都返回相同的代码块(x * x),所以这个例子并没有太多实际意义,但它展示了 _Generic() 的基本用法。

2.3 注意事项

  1. 类型匹配_Generic() 会根据表达式的静态类型来选择分支,而不是运行时类型。
  2. 默认分支:必须提供一个 default 分支,以处理未明确列出的类型。
  3. 类型安全_Generic() 选择器提供了类型安全的方式,因为它在编译时就确定了要执行的代码。

_Generic() 是 C11 标准中一个强大的特性,它允许开发者编写更灵活和可重用的代码。然而,它的使用可能会使代码的阅读和理解变得更加困难,因此应该在确实需要时才使用。