C语言基础语法复习03-c11新特性详解

https://www.runoob.com/cprogramming/c-intro.html
C11(也被称为C1X)指ISO标准ISO/IEC 9899:2011。
在它之前的C语言标准为C99。
新特性:

对齐处理(Alignment)的标准化(包括_Alignas标志符,alignof运算符,aligned_alloc函数以及<stdalign.h>头文件)。

_Noreturn 函数标记,类似于 gcc 的 __attribute__((noreturn))_Generic 关键字。

多线程(Multithreading)支持,包括:
_Thread_local存储类型标识符,<threads.h>头文件,里面包含了线程的创建和管理函数。
_Atomic类型修饰符和<stdatomic.h>头文件。

增强的Unicode的支持。基于C Unicode技术报告ISO/IEC TR 19769:2004,增强了对Unicode的支持。包括为UTF-16/UTF-32编码增加了char16_tchar32_t数据类型,提供了包含unicode字符串转换函数的头文件<uchar.h>。

删除了 gets() 函数,使用一个新的更安全的函数gets_s()替代。

增加了边界检查函数接口,定义了新的安全的函数,例如 fopen_s()strcat_s() 等等。

增加了更多浮点处理宏()。

匿名结构体/联合体支持。这个在gcc早已存在,C11将其引入标准。

静态断言(Static assertions),_Static_assert(),在解释 #if 和 #error 之后被处理。

新的 fopen() 模式,("…x")。类似 POSIX 中的 O_CREAT|O_EXCL,在文件锁中比较常用。

新增 quick_exit() 函数作为第三种终止程序的方式。当 exit()失败时可以做最少的清理工作。

alignas alignof aligned_alloc示例

_Alignas(double) int x; //按 double 类型的对齐方式对齐。
alignas(double) int x;
size_t a = alignof(int); //alignof 返回一个类型的对齐要求

#include <stdlib.h>
int* arr = (int*)aligned_alloc(alignof(int), sizeof(int) * 100);//动态内存分配函数

<stdalign.h> 头文件:
alignas:作为 _Alignas 的同义词存在。
alignof:作为 _Alignof 的同义词存在。

_Noreturn 函数标记示例

_Noreturn 的前身:编译器特定的扩展,例如GCC的__attribute__((noreturn))
_Noreturn void exitWithError(const char* message) {
    printf("%s\n", message);
    exit(1);//不返回(无限循环或异常终止)
}

_Generic 关键字

_Generic 关键字是一个通用选择表达式,允许基于表达式的类型选择结果。它在某些情况下可以被视为编译时的 switch 语句,专门用于类型。
_Generic 提供了一种强大的机制来在编译时根据类型进行决策,这使得宏可以更加智能和灵活。

#define typename(x) _Generic((x),        \
        char: "char",                    \
        int: "int",                      \
        double: "double",                \
        default: "other")
        
#define square(x) _Generic((x),       \
        int: (x) * (x),               \
        float: (x) * (x),             \
        double: (x) * (x))

多线程(Multithreading)支持
threads.h stdatomic.h _Atomic类型 _Thread_local存储类型

_Thread_local 使得每个线程都有其独特的变量实例。
这意味着对于标记为 _Thread_local 的变量,每个线程都有其独立的副本。

<threads.h> 提供了线程的创建、管理和同步的功能。

thrd_create:创建一个新线程。
thrd_join:等待线程完成。
mtx_t 和相关函数:用于创建和管理互斥锁,用于线程同步。

_Atomic 修饰符和 <stdatomic.h> 头文件提供了一套原子类型和操作
#include <stdio.h>
#include <stdatomic.h>
#include <threads.h>
atomic_int counter = ATOMIC_VAR_INIT(0);

int increment(void* times) {
    for(int i = 0; i < *(int*)times; i++) {
        atomic_fetch_add(&counter, 1);
    }
    return 0;
}
int main() {
    thrd_t t1, t2;
    int times = 100000;
    thrd_create(&t1, increment, &times);
    thrd_create(&t2, increment, &times);
    thrd_join(t1, NULL);
    thrd_join(t2, NULL);
    printf("Counter value: %d\n", atomic_load(&counter));
    return 0;
}

unicode支持,以前需要iconv之类的库

#include <stdio.h>
#include <uchar.h>
int main() {
    char16_t utf16_source[] = u"\u03B1";  // Greek letter alpha in UTF-16
    char mb_dest[MB_CUR_MAX];
    mbstate_t state = { 0 };
    size_t bytes = c16rtomb(mb_dest, utf16_source[0], &state);
    if (bytes != (size_t)-1) {
        mb_dest[bytes] = '\0'; // Null-terminate the multi-byte string
        printf("UTF-16 to multi-byte: %s\n", mb_dest);
    }
    return 0;
}

删除了 gets() 函数,使用更安全的函数gets_s()替代。

从标准输入读取一行文本并将其存储在指定的字符数组中,但它有一个严重的缺陷:gets()函数不检查缓冲区的大小,这可能导致缓冲区溢出。
char buffer[10];
gets(buffer);    
gets_s(buffer, sizeof(buffer));

fopen_s(),strcat_s() 等边界检查函数接口,安全函数

以 _s 为后缀,表示它们是标准函数的"安全"版本safe
FILE *file;
errno_t err = fopen_s(&file, "example.txt", "r");
errno_t err = strcat_s(dest, sizeof(dest), src);
errno_t err = strcpy_s(dest, sizeof(dest), src);

c11浮点处理宏

<float.h> 头文件中定义。它们为开发者提供了更细粒度的浮点行为控制。
C11中新增的一些浮点宏的示例:
浮点异常宏:这些宏表示浮点异常的不同类型。当某个浮点操作产生异常时,相应的标志会被设置。
FE_DIVBYZERO: 除以零的异常。
FE_INEXACT: 结果不能精确表示的异常。
FE_INVALID: 例如,对于非数(NaN)的操作产生的异常。
FE_OVERFLOW: 结果超出类型的正范围时的异常。
FE_UNDERFLOW: 结果是正数,但是太小,不能表示为规范化值时的异常。

浮点环境函数:这些函数提供了浮点环境的查询和控制。例如,你可以使用 fesetexceptflag()fegetexceptflag() 来设置和查询浮点异常标志。

浮点舍入模式:这些宏表示不同的舍入模式。
FE_DOWNWARD: 向负无穷大方向舍入。
FE_TONEAREST: 向最近的值舍入,如果有两个相同近的值,则向偶数方向舍入。
FE_TOWARDZERO: 向零舍入。
FE_UPWARD: 向正无穷大方向舍入。

#include <stdio.h>
#include <fenv.h>
#include <float.h>
int main() {
    #ifdef FE_UPWARD
    if (fesetround(FE_UPWARD)) {//设置舍入模式为向上舍入
        printf("Error in setting the rounding mode!\n");
        return 1;
    }
    double x = 2.4;
    double y = 2.6;
    printf("2.4 rounds to %f\n", nearbyint(x));  // Prints: 2.4 rounds to 3.000000 根据当前的舍入模式来舍入浮点数
    printf("2.6 rounds to %f\n", nearbyint(y));  // Prints: 2.6 rounds to 3.000000 根据当前的舍入模式来舍入浮点数
    #else
    printf("FE_UPWARD is not supported.\n");
    #endif
    return 0;
}

匿名结构体/联合体、static_assert、fopen(x)

匿名结构体/联合体支持。这个在gcc早已存在,C11将其引入标准。
实际msvc 2003年左右就支持。原理是,编译器没有所谓的structunion概念,
只是用于解释内存的组织方式,类名只是编译期的标识,
对象名也只在编译期有用,实际汇编层面都是直接地址访问,编译期就根据代码计算好了偏移。

静态断言(Static assertions),_Static_assert(),在解释 #if 和 #error 之后被处理。
这个类似cpp中的static_assert,编译期运行,可验证代码的正确性,不同编译环境的正确性。

新的 fopen() 模式,("…x")。类似 POSIX 中的 O_CREAT|O_EXCL。
如果文件已经存在,fopen()函数会返回NULL,并设置相应的错误。

quick_exit()函数

在C11之前,C语言提供了两种主要的程序终止方式:exit()abort(). 
exit()函数会清理所有已注册的退出处理程序、关闭所有打开的文件流等,并终止程序。
abort()则会直接终止程序,而不进行清理。

quick_exit()函数介于两者之间,一个可以快速退出程序但执行一些最小清理工作的方法。
quick_exit()允许注册一些退出处理函数(使用at_quick_exit()函数),这些函数在quick_exit()调用时执行,但不会执行使用atexit()注册的处理函数。

#include <stdio.h>
#include <stdlib.h>
void on_quick_exit_func(void) {
    printf("Function executed on quick_exit()\n");
}
void on_exit_func(void) {
    printf("Function executed on exit()\n");
}
int main() {
    at_quick_exit(on_quick_exit_func);
    atexit(on_exit_func);
    printf("Main function processing...\n");
    if (/* some condition */) {
        printf("Quickly exiting...\n");
        quick_exit(0);  // This will execute only on_quick_exit_func()
    }
    printf("Normal exit...\n");
    exit(0);  // This would execute on_exit_func()
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值