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 注意事项¶
- 类型匹配:
_Generic()
会根据表达式的静态类型来选择分支,而不是运行时类型。 - 默认分支:必须提供一个
default
分支,以处理未明确列出的类型。 - 类型安全:
_Generic()
选择器提供了类型安全的方式,因为它在编译时就确定了要执行的代码。
_Generic()
是 C11 标准中一个强大的特性,它允许开发者编写更灵活和可重用的代码。然而,它的使用可能会使代码的阅读和理解变得更加困难,因此应该在确实需要时才使用。