首页 > 其他分享 >C语言C23版的最新特性

C语言C23版的最新特性

时间:2024-12-12 22:56:47浏览次数:12  
标签:C23 include return 示例 int 特性 C语言 类型 main

C23 是 ISO C 标准的最新修订版,在 C17 的基础上进行了一些改进和扩展,以下是 C23 的一些新特性。

一、新的类型

1.十进制浮点数类型:引入了_Decimal32、_Decimal64和_Decimal128三种新的十进制浮点数类型,可用于需要精确十进制计算的场景,如金融计算等,能减少二进制浮点数在十进制表示时的舍入误差。

示例:在金融计算中,精确的十进制计算非常重要。例如计算银行利息,假设本金为$1000.00,年利率为3.0%,存期为2年,使用`_Decimal32类型计算利息。

        #include <stdio.h>
        #include <stdlib.h>
        #include <decimal.h>
        int main() {
            _Decimal32 principal = 1000.00DF;
            _Decimal32 interest_rate = 0.03DF;
            _Decimal32 interest = principal * interest_rate * 2;
            printf("The interest earned is: %f\n", (double)interest);
            return 0;
        }

 这里`DF`是`_Decimal32`类型的后缀,通过这种类型可以更精确地进行十进制小数的运算,避免二进制浮点数转换带来的舍入误差。

2.位精确整数类型:增加了_BitInt(n)和unsigned _BitInt(n)类型用于表示位精确的整数,还添加了_BitInt_max_width宏来表示最大位宽,以及ckd_add()、ckd_sub()、ckd_mul()等用于检查整数操作的宏,有助于进行更精确的位级操作和整数运算。

示例:假设要对一个32位的数据进行位操作,并且希望确保整数类型的位宽精确。

        #include <stdio.h>
        #include <stdint.h>
        #include <stdbit.h>
        int main() {
            _BitInt(32) bit_int = 0b10101010101010101010101010101010;
            // 计算位为1的个数
            size_t count_ones = __STDC_count_ones(bit_int);
            printf("The number of bits set to 1 is: %zu\n", count_ones);
            return 0;
        }

这个例子展示了如何使用`_BitInt`类型定义一个位精确的整数,并使用新的位操作函数`__STDC_count_ones`计算其中位为1的个数。 

3.nullptr_t 类型:新增了nullptr_t类型,nullptr是其对应的常量,用于更明确地表示空指针,避免了使用NULL可能带来的混淆。

示例:在指针操作中更明确地表示空指针。

        #include <stdio.h>
        int main() {
            int *ptr = nullptr;
            if (ptr == nullptr) {
                printf("The pointer is null.\n");
            }
            return 0;
        }

这里使用`nullptr`来初始化指针并进行比较,避免了以前`NULL`可能带来的混淆,因为`NULL`在某些情况下可能被定义为0,这可能导致意外的整数和指针的比较。 

二、新的常量表示

1.二进制整数常量:允许使用二进制前缀0b或0B来表示整数常量,使位操作的表示更加直观清晰,方便对二进制数据进行处理。

示例:在进行位掩码操作时,二进制常量表示很方便。例如,要设置一个字节的第3位(从0开始计数)和第5位为1。

        #include <stdio.h>
        int main() {
            unsigned char byte = 0b00001010;
            printf("The binary value of byte is: %d\n", byte);
            return 0;
        }

这种二进制表示方式让位操作的意图更加清晰,相比十六进制或十进制表示更直观地展示了位的设置情况。 

2.u8 字符常量:引入了使用u8前缀的 UTF-8 字符串字面量,更好地支持 UTF-8 编码的字符处理,便于国际化文本的表示和处理。

示例:在处理UTF - 8编码的文本时,使用`u8`前缀。例如,打印一个包含UTF - 8编码的汉字“好”。

        #include <stdio.h>
        int main() {
            char utf8_char[] = u8"好";
            printf("The UTF - 8 character is: %s\n", utf8_char);
            return 0;
        }

这样可以方便地在C语言中处理UTF - 8编码的字符,对于国际化文本处理很有用。 

三、新的初始化方式

        空初始化列表:允许使用空的初始化列表{ }来初始化对象,对于具有默认初始值设置的结构体等类型,这种语法更加简洁明了,能更方便地将对象初始化为默认状态。

示例:初始化一个结构体。假设定义一个结构体表示二维坐标点。

        struct Point {
            int x;
            int y;
        };
        int main() {
            struct Point p = {};
            printf("The point coordinates are: (%d, %d)\n", p.x, p.y);
            return 0;
        }

这里使用空初始化列表将结构体`p`的成员初始化为0,这种方式对于有默认初始值设置的结构体更加简洁。 

四、新的属性

        引入了((nodiscard))、((maybe_unused))、((deprecated))等新属性。例如((nodiscard))属性可用于提醒开发者注意函数返回值的处理,避免忽略重要的返回值而导致潜在错误。

示例(nodiscard属性):定义一个函数用于打开文件并返回文件指针,使用`((nodiscard))`属性提醒开发者处理返回值。

    __attribute__((nodiscard)) FILE* open_file(const char* filename) {
        FILE* file = fopen(filename, "r");
        if (file == NULL) {
            perror("Error opening file");
        }
        return file;
    }
    int main() {
        open_file("test.txt"); 
        // 编译器会警告返回值被忽略,因为函数有((nodiscard))属性
        return 0;
    }

编译器会警告返回值被忽略,因为函数有((nodiscard))属性 return 0; } ``` - 这可以帮助开发者避免因忽略重要的返回值而导致的潜在错误。 

五、新的关键字和语法

_Static_assert 关键字:将_Static_assert从宏转变为关键字,用于在编译时进行静态断言检查,可更方便地验证程序中的条件是否满足,增强了代码的健壮性。

示例:检查结构体大小是否符合预期。假设定义一个结构体用于存储一些数据。

        struct Data {
            int a;
            char b;
        };
        int main() {
            _Static_assert(sizeof(struct Data) >= sizeof(int) + sizeof(char), "Structure size is too small");
            return 0;
        }

如果结构体大小不符合条件,编译器会在编译时给出错误提示,帮助开发者在早期发现问题。 

typeof 关键字:引入了typeof关键字,用于指定类型,可根据已有变量的类型来定义新变量,使代码在处理不同类型但相关的数据时更加灵活和方便。

示例:根据已有的变量类型定义新变量。

        #include <stdio.h>
        int main() {
            int a = 5;
            typeof(a) b = 10;
            printf("The value of b is: %d\n", b);
            return 0;
        }

这里`b`的类型根据`a`的类型确定为`int`,`typeof`关键字使代码在处理相关类型的变量时更加灵活。 

改进的 auto 关键字:其含义被改变为既可以进行类型推断,同时在与类型一起使用时仍保留其作为存储类说明符的旧含义,但与 C++ 不同的是,C23 仅允许对对象定义进行类型推断,而不能推断函数返回类型或函数参数类型。

示例:在C23中,`auto`可以用于对象定义的类型推断。

        int main() {
            auto i = 5;  // i被推断为int类型
            auto arr[] = {1, 2, 3};  // arr被推断为int数组
            return 0;
        }

与C++不同,C23的`auto`不能推断函数返回类型或函数参数类型。 

六、新的预处理器指令

增加了#elifdef、#elifndef、#warning、#embed、__has_embed、__has_include、__has_c_attribute、__va_opt__等预处理器指令和宏。#elifdef和#elifndef可用于创建更灵活的条件编译判断;#warning可用于输出警告信息;#embed可用于将二进制资源嵌入到程序中,方便处理如图片、音频等资源文件。

示例(#embed指令):假设要将一个文本文件的内容嵌入到程序中。

    #embed "test.txt"
    int main() {
        // 在这里可以使用嵌入的文件内容进行后续处理
        return 0;
    }

具体如何处理嵌入的内容取决于程序的需求,例如可以是配置文件内容、文本资源等。`#embed`指令为处理二进制资源提供了方便的方式。 

七、标准库的增强

        新函数:添加了memset_explicit()函数用于安全地擦除敏感数据;memccpy()函数用于高效地连接字符串;strdup()和strndup()函数用于分配字符串的副本;mem_alignment()函数用于确定指针的字节对齐;还在<stdbit.h>头文件中添加了一系列位操作的实用函数、宏和类型,如__STDC_count_ones*()、__STDC_count_zeros*()等用于位计数和查找的函数。

示例(memset_explicit函数):安全地擦除敏感数据。假设定义一个数组用于存储敏感信息,如密码。

        #include <stdio.h>
        #include <string.h>
        int main() {
            char password[10] = "secret";
            memset_explicit(password, 0, sizeof(password));
            printf("The password has been erased.\n");
            return 0;
        }

       现有函数的改进:为printf()和scanf()函数家族添加了%b二进制转换说明符,以及为strtol()和wcstol()函数家族添加了对0b和0B二进制转换的支持;同时规定bsearch()、bsearch_s()、memchr()、strchr()等一系列函数在传入const对象时应返回const限定的对象。

示例(printf函数的%b转换说明符):以二进制形式输出整数。

        #include <stdio.h>
        int main() {
            int num = 10;
            printf("The binary representation of %d is: %b\n", num, num);
            return 0;
        }

新增的`%b`转换说明符使输出二进制数据更加方便,无需手动转换。 

八、其他特性

更好的数组和 const 支持:提供了对使用const与数组的更好支持,以及对可变修改类型(除了自动变量分配在栈上的可变长度数组之外)的强制支持,使数组的使用更加灵活和安全。

 示例:使用`const`修饰数组参数,保证函数内部不会修改数组内容。

        void print_array(const int arr[], size_t size) {
            for (size_t i = 0; i < size; ++i) {
                printf("%d ", arr[i]);
            }
            printf("\n");
        }
        int main() {
            int arr[] = {1, 2, 3};
            print_array(arr, sizeof(arr)/sizeof(arr[0]));
            return 0;
        }

这种方式增强了代码的安全性,确保函数不会意外修改传入的数组。 

类型兼容性规则的改变:更改了结构、联合和枚举类型的兼容性规则,允许使用相同标签重新声明兼容类型,这在一些复杂的类型定义和重定义场景中提供了更多的灵活性。

示例:重新声明兼容类型的结构体。

        struct MyStruct;
        struct MyStruct {
            int a;
        };
        int main() {
            struct MyStruct s = {1};
            return 0;
        }

这种规则的改变在复杂的类型定义和重定义场景中提供了更多灵活性,允许开发者在一定条件下重新声明结构体等类型。 

标签:C23,include,return,示例,int,特性,C语言,类型,main
From: https://blog.csdn.net/easydvlp/article/details/144437239

相关文章

  • 专为高性能汽车设计的Armv9架构的Neoverse V3AE CPU基础知识与软件编码特性解析
    一、ARMv9以及V3AE处理器架构Armv9架构的ArmNeoverseV系列处理器是专为高性能计算设计的产品线,其中V3AE(AdvancedEfficiency)特别强调了性能与效率之间的平衡。以下是关于Armv9架构下NeoverseV3AE处理器结构和指令集的一些详细解读:Armv9架构概述Armv9是ARM最新一代......
  • 用C语言实现栈:从基础到实战
    栈(Stack)是一种基础的数据结构,遵循后进先出(LIFO,LastInFirstOut)的原则。它被广泛应用于函数调用、表达式求值、括号匹配等问题中。在这篇技术博客中,我们将详细介绍如何使用C语言实现一个栈,并涵盖基本的操作以及实战应用。什么是栈?栈是一种特殊的线性表,只允许在一端进行插入和......
  • C语言数组
    目录数组的初始化数组的引用二维数组二维数组的初始化二维数组的引用在C语言中,数组它可以存储一系列相同类型的数据,数组中的每个元素都有一个索引,索引通常从0开始,定义数组会分配内存,数组名表示内存的首地址;数组的初始化Inta[5]={1,2,3,4,5};这个元素是1,2,3,4,5这......
  • 面试必会(嵌入式)-C语言面试高频(内存管理)
    1.(内存)堆和栈的区别⭐堆栈空间分配不同:栈由操作系统自动进行分配和释放,用于存放函数的参数值、局部变量的值等,具有高效性。堆:一般由程序员手动进行分配和释放,效率比栈低很多。data数据区:存放全局变量,静态变量。堆栈缓存方式不同:栈使用一级缓存,存储在处理器核心中,调用完......
  • C语言(内存管理)
    main函数原型定义:main函数有多种定义格式,main函数也是函数,函数相关的结论对main函数也有效(也可以定义main函数的函数指针)。main函数的完整写法:intmain(intargc,char*argv[]){}intmain(intargc,char**argv){}扩展写法:main(){}等价intmain(){}intmain......
  • 链表的一步步实现(需有一部分c语言基础)【缓慢更新中
    链表的一步步实现(需有一部分c语言基础)(由于本人上课实在没学懂链表的具体实现步骤,于是写下这篇博客记录学习过程,有兴趣的新手也可以跟着学习1.认识链表的结构&创建简单静态链表并输出数据Q:什么是链表?A:链表是由一系列节点组成,每个节点包含两个域,一个是数据域,用来保存数据,另外一......
  • C语言-排序
    常见的排序算法分为以下四种,插入排序,选择排序,交换排序,归并排序。一、插入排序(一)直接插入排序直接插入排序,将一段数组看做被分成已排序序列和未排序序列,排序过程是从未排序序列的元素开始,该元素与已排序序列的元素从后向前扫描,找到第一个小于(或大于)该元素的已排序项,然后将......
  • C语言:指针(2)
    字符数组和字符指针字符串的实现在C语言中,表示一个字符串有以下两种形式:用字符数组存放一个字符串,用字符指针指向一个字符串案例:/***字符串的两种实现方式*/ //方式1:使用字符数组实现字符串 charstr[]="ILOVRYOU"; printf("%s\n",str); //使用字符指针实现字......
  • C语言基础:数组(一维数组)
    引例如果我们要在程序中表示一个学生的成绩,我们会使用一个int来表示,如:intscore。假如我们要在程序中表示一组成绩,此时我们所学的常规的数据类型就无法再表示,这个时候我们就需要使用到一种新的表现形式,这种表现形式就是我们的数组。什么是数组数组是相同类型,有序数据的集合......
  • C语言基础:数组(二维数组)
    数组二维数组定义:二维数组本质上是一个行列式的组合,也就是说二维数组是由行和列两部分组成。二维数组数据是通过行列解读。二维数组可被视为一个特殊的一维数组,相当于二维数组又是一个一维数组,只不过它的元素是一维数组。(也就是说数组的元素可以是数组类型)。语法 类型......