C语言编程新特性与实用技巧
1. 运算限制与函数返回规则
在某些运算中,除法操作不被支持,并且仅适用于除普通字符(plain char)、布尔类型(bool)或位精确整数(bit - precise integers)之外的整数类型。Type1、Type2 和 Type3 可以是不同的类型。这些函数在运算的数学结果可以由 Type1 表示时返回 false,否则返回 true。虽然这些函数有助于遵循相关的编码标准和准则,但在组合操作时仍存在一定的不便。
2. unreachable 类函数宏
unreachable
类函数宏在
<stddef.h>
中提供。它会展开为一个 void 表达式,在执行过程中到达该表达式会导致未定义行为。这可以为优化器提供关于无法到达的流控制的提示,但使用时需谨慎,因为优化器会相信你给出的假设,即使假设错误。以下是一个典型的使用示例:
#include <stdlib.h>
enum Color { Red, Green, Blue };
int func(enum Color C) {
switch (C) {
case Red: return do_red();
case Green: return do_green();
case Blue: return do_blue();
}
unreachable(); // 未处理的值
}
3. 位和字节实用工具
C23 在
<stdbit.h>
头文件中引入了一系列位和字节实用工具,具体功能如下:
- 统计位模式中 1 或 0 的数量
- 统计前导或尾随 1 或 0 的数量
- 查找第一个前导或尾随 1 或 0
- 测试单个位是否被设置
- 确定表示一个值所需的最小位数
- 根据一个值确定下一个最小或最大的 2 的幂
例如,以下代码可用于统计一个值从最高有效位开始的连续 0 位的数量:
#include <stdbit.h>
void func(uint32_t V) {
int N = stdc_leading_zeros(V);
// 使用前导零计数 N
}
在 C23 之前,实现相同功能的代码更为复杂:
void func(uint32_t V) {
int N = 32;
unsigned R;
R = V >> 16;
if (R != 0) { N -= 16; V = R; }
R = V >> 8;
if (R != 0) { N -= 8; V = R; }
R = V >> 4;
if (R != 0) { N -= 4; V = R; }
R = V >> 2;
if (R != 0) { N -= 2; V = R; }
R = V >> 1;
if (R != 0) N -= 2;
else N -= V;
// 使用前导零计数 N
}
4. IEEE 浮点支持
C23 通过集成 TS 18661 - 1、2 和 3 更新了 IEEE 浮点支持。现在,附录 F 与 IEEE 浮点算术标准(IEEE 754 - 2019)保持一致,并且也适用于十进制浮点数(
_Decimal32
、
_Decimal64
和
_Decimal128
)。不过,不能将十进制运算与二进制、复数或虚数浮点数混合使用。附录 H 支持交换、扩展浮点类型和非算术交换格式,允许使用 binary16、图形处理单元(GPU)数据、二进制或十进制表示。
数学库的更改支持对
_DecimalN
、
_FloatN
和
_FloatNx
类型的
<math.h>
操作。新增了特殊的指数、对数、幂和基于 π 的三角函数变体,改进了用于最小/最大、全序和数值属性测试的函数,以及允许对浮点值与整数或字符串之间的转换进行细粒度控制的函数。
此外,新增了
memset_explicit
函数,用于在确实需要清除内存时使用。它与
memset
相同,但优化器不能移除对它的调用。
strdup
和
strndup
函数从 POSIX 中被采用。
4.1 部分 C 语言特性总结表格
| 特性 | 描述 |
|---|---|
| unreachable 宏 |
在
<stddef.h>
中,为优化器提供流控制提示,执行到展开表达式会导致未定义行为
|
| 位和字节实用工具 |
在
<stdbit.h>
中,提供多种位和字节操作功能
|
| IEEE 浮点支持 | 集成相关标准,附录 F 与 IEEE 标准一致,数学库有新增功能 |
| memset_explicit 函数 | 用于清除内存,优化器不能移除调用 |
| strdup 和 strndup 函数 | 从 POSIX 采用 |
4.2 位和字节实用工具使用流程图
graph TD;
A[开始] --> B[包含 <stdbit.h> 头文件];
B --> C[定义 uint32_t 类型变量 V];
C --> D[调用 stdc_leading_zeros(V) 函数];
D --> E[获取前导零计数 N];
E --> F[使用前导零计数 N];
F --> G[结束];
5. 其他语言特性与操作
5.1 类型与运算符相关
-
算术类型
:包括整数、浮点等类型。整数类型有不同的表示范围和精度,如
int、long等,其转换规则较为复杂,涉及到整数提升、通常算术转换等。例如,在进行算术运算时,不同类型的操作数会先进行转换,遵循一定的转换规则,以保证运算的正确性。 -
运算符
:C 语言有丰富的运算符,如算术运算符(
+、-、*、/等)、位运算符(&、|、^等)、逻辑运算符(&&、||、!等)。运算符有优先级和结合性,在表达式求值时需要遵循这些规则。例如,a + b * c会先计算b * c,因为乘法运算符的优先级高于加法运算符。
5.2 存储相关
-
存储类
:C 语言有多种存储类,如
auto、static、extern、register等。不同的存储类决定了变量的存储位置、生命周期和作用域。例如,static变量在程序的整个执行期间都存在,而auto变量在其所在的代码块执行结束后就会被销毁。 -
内存管理
:可以使用
malloc、calloc、realloc和free等函数进行动态内存分配和释放。例如,使用malloc分配内存:
#include <stdlib.h>
int main() {
int *ptr = (int *)malloc(sizeof(int));
if (ptr != NULL) {
*ptr = 10;
free(ptr);
}
return 0;
}
5.3 输入输出相关
-
文件操作
:可以使用
fopen、fclose、fread、fwrite等函数进行文件的打开、关闭、读写操作。例如,读取文件内容:
#include <stdio.h>
int main() {
FILE *fp = fopen("test.txt", "r");
if (fp != NULL) {
char ch;
while ((ch = fgetc(fp)) != EOF) {
printf("%c", ch);
}
fclose(fp);
}
return 0;
}
-
格式化输入输出
:使用
printf和scanf等函数进行格式化的输入输出。例如,输出整数和字符串:
#include <stdio.h>
int main() {
int num = 10;
char str[] = "Hello";
printf("Number: %d, String: %s\n", num, str);
return 0;
}
5.4 部分特性总结表格
| 特性分类 | 具体特性 | 描述 |
|---|---|---|
| 类型与运算符 | 算术类型 | 包含整数、浮点等类型,有复杂的转换规则 |
| 运算符 | 丰富的运算符,有优先级和结合性 | |
| 存储 | 存储类 |
如
auto
、
static
等,决定变量存储位置、生命周期和作用域
|
| 内存管理 |
使用
malloc
等函数进行动态内存分配和释放
| |
| 输入输出 | 文件操作 |
使用
fopen
等函数进行文件读写
|
| 格式化输入输出 |
使用
printf
和
scanf
进行格式化操作
|
5.5 文件读取操作流程图
graph TD;
A[开始] --> B[使用 fopen 打开文件];
B --> C{文件是否打开成功};
C -- 是 --> D[使用 fgetc 读取文件内容];
D --> E{是否到达文件末尾};
E -- 否 --> F[输出读取的字符];
F --> D;
E -- 是 --> G[使用 fclose 关闭文件];
G --> H[结束];
C -- 否 --> H;
6. 总结
C 语言具有丰富的特性和强大的功能,涵盖了运算、存储、输入输出等多个方面。新特性如位和字节实用工具、IEEE 浮点支持等为编程带来了更多的便利和功能扩展。同时,了解和掌握 C 语言的基本特性,如类型、运算符、存储类等,对于编写高效、正确的程序至关重要。在实际编程中,需要根据具体需求合理运用这些特性和工具,以实现所需的功能。
超级会员免费看

被折叠的 条评论
为什么被折叠?



