C 编程语言是最成熟且最流行的编程语言之一。它比较容易学习,而且实用性很强。
也许令人惊讶的是,C 编程语言一直在缓慢而谨慎地发展。如果您有 GCC 23 或 LLVM (Clang) 16,那么您已经拥有一个具有最新标准 (C23) 的一些功能的编译器。
// 仅包含 stdio.h(如果存在) # if __has_include ( < stdio.h > ) _ _ #包含< stdio.h > #万一 #包含< stdlib.h > [ [已弃用] ] 无效f ( ) { } [ [不丢弃] ] int g ( int x ) { 返回x + 1 ; } int main() { F ( ) ; // 编译时警告:'f' 已弃用 克( 1 ) ; // 编译时警告 自动 x = 0 b 1111 ; 类型( x ) y = 1 '000' 000 ; // y 的类型与 x 相同 printf ( "%d \n " , x ) ; // 打印 15 printf ( "%d \n " , y ) ; // 打印 1000000 constexpr int N = 10 ; // 使用 static_assert 进行编译时断言 static_assert ( N == 10 , "N 必须是 10 " ) ; 布尔a [ N ] ; // N 个布尔值的数组 for ( int i = 0 ; i < N ; + + i ) { a [ i ] = true ; } printf ( "%d \n " , a [ 0 ] ) ; // 打印 1 }
- 代码的第一部分包含一些预处理器指令,这些指令是编译器在编译源代码之前对其进行处理的指令。 #if指令在编译时检查条件,并且仅当条件为真时才包含以下代码。 __has_include宏是 C23 采用的 C++17 的一项功能,用于检查头文件是否存在并可以包含。在这种情况下,它没有用,因为我们知道stdio.h存在,但在其他情况下,这对于确定可用的标头很有用。
- 代码的下一部分定义了两个带有属性的函数,这些属性是注释,为编译器提供有关函数、变量、类型等的行为或用法的附加信息。
- [[deprecated]] 属性是 C23 采用的 C++14 的一项功能,它将函数标记为已过时并阻止其使用。如果调用或引用该函数,编译器将发出警告。
- [[nodiscard]] 属性是 C23 采用的 C++17 的一项功能,表示函数的返回值不应被忽略或丢弃。如果从废弃值表达式调用该函数,编译器将发出警告。
在这种情况下,函数 f 已被弃用并且不执行任何操作,而函数 g 返回输入值加一,不应被忽略。主函数的前两行调用函数 f 和 g 并触发警告。
- main 函数的第三行使用 auto 关键字声明变量 x,这是 C++11 的一项功能,可让编译器从变量的初始值设定项推断变量的类型。在这种情况下,初始值设定项是二进制文字,这是 C++14 的一项功能,并被 C23 采用,允许使用前缀 0b 以二进制表示法写入整数常量。 x的值为0b1111,相当于十进制的15。
- 第四行使用 typeof 运算符声明另一个变量 y,该运算符返回表达式的类型。在本例中,表达式为 x,因此 y 的类型与 x 的类型相同。 y 的初始值设定项是数字分隔符,这是 C23 采用的 C++14 的一项功能,允许在数字文字中的数字之间插入单引号以提高可读性。 y 的值为 1’000’000,相当于十进制的 1000000。
- 第七行用constexpr关键字声明了一个常量变量N,这是C23采用的C++11的一个特性,表明可以在编译时计算该变量的值。 N 的值为10。以前,人们经常使用宏来定义编译时常量(例如#define N 10 )。
- 第八行使用 static_assert 关键字,这是 C23 采用的 C++11 的一个功能,用于执行编译时断言检查。该关键字采用布尔表达式和可选字符串消息作为参数。如果表达式为 false,编译器将发出错误并停止编译,并显示消息。如果表达式为真,编译器将不执行任何操作。在本例中,表达式为 N == 10,为真,因此编译继续。
- 第九行声明了一个名为 a 的 N 个布尔值数组。数组是存储在连续内存位置的相同类型元素的集合。数组的大小必须是常量表达式,这就是为什么 N 用 constexpr 声明。我们还使用关键字 true 和 false,它们成为 C23 中的标准。
C23 中还有更多功能,但编译器和系统库需要一些时间才能跟上。
到目前为止我的想法:
- 在 C 中引入 consexpr 可能有助于减少对宏的依赖,这通常是一个好主意。宏在 C 中运行良好,但是当引入错误时,可能很难获得有意义的错误消息。这种情况不会经常发生,但在大型代码库中,这可能会成为一个问题。
- 我个人很少在其他语言中使用 auto 和 typeof,因此我不希望在 C 中使用它们。但是,在某些特定情况下,它可以极大地简化代码。这可能有助于减少对宏的依赖。
- static_assert 背后的想法很棒。您运行的检查不会影响软件的性能,甚至可能会有所帮助。它很便宜,而且可以捕捉讨厌的虫子。它对于 C 来说并不陌生,但采用 C++ 语法是一个好主意。
- __has_include功能可以简化对不同编译器的支持。这是个好主意。
原文: https://lemire.me/blog/2024/01/21/c23-a-slightly-better-c/