首页 > 其他分享 >C99 版本特性

C99 版本特性

时间:2024-07-25 21:54:16浏览次数:15  
标签:main return int C99 特性 版本 printf include


title: C99 版本特性
date: 2021-07-26 16:00:00


前言

本文性质为学习总结,若有错误敬请指正。

目录

  1. C语言版本历史
  2. C99 主要特性
  3. 新特性示例代码
  4. 文末

C主要版本

C 语言的标准化过程由国际标准化组织(ISO)和国际电工委员会(IEC)负责。以下是 C 语言各个版本的主要顺序:

  1. K&R C(1978年):

    • 由 Brian Kernighan 和 Dennis Ritchie 编写的《The C Programming Language》一书中定义的版本,通常被称为“K&R C”。
  2. C89/C90(1989/1990年):

    • 也称为 ANSI C 或 ISO C,是第一个被国际标准化组织(ISO)采纳的 C 语言标准。
    • 标准文档为 ISO/IEC 9899:1990。
  3. C95(1995年):

    • 对 C90 的一个小修订,主要增加了对 Unicode 的支持。
    • 标准文档为 ISO/IEC 9899:1990/Amd 1:1995。
  4. C99(1999年):

    • 引入了许多新特性,包括内联函数、变长数组(VLA)、复数类型、泛型选择等。
    • 标准文档为 ISO/IEC 9899:1999。
  5. C11(2011年):

    • 引入了多线程支持、_Static_assert、_Generic 关键字等新特性。
    • 标准文档为 ISO/IEC 9899:2011。
  6. C18(2018年):

    • 对 C11 的一个技术修订,主要包含了一些勘误和澄清,没有引入新的语言特性。
    • 标准文档为 ISO/IEC 9899:2018。

每个版本的 C 语言标准都在前一个版本的基础上进行了扩展和改进,以适应新的编程需求和技术发展。国内相关C语言书籍主要采用 C89/C90 标准。GCC编译器支持C99标准,但默认使用C89标准。使用 -std=c99 选项可以指定使用C99标准。

C99主要版本特性简述

C99 标准引入了许多新内容,以下是一些主要的特性:

  1. _Bool 类型:引入了 _Bool 类型,用于表示布尔值。

  2. stdbool.h 头文件:提供了 booltruefalse 宏,使得布尔类型的使用更加方便。

  3. 变长数组(VLA):允许数组的大小在运行时确定。

  4. 复合字面量:允许在表达式中直接创建结构体或数组的临时对象。

  5. 内联函数:通过 inline 关键字支持内联函数。当编译器遇到内联函数的调用时,它会将函数的代码直接插入到调用该函数的地方,而不是像普通函数那样通过函数调用机制来执行。这样可以减少函数调用的开销,提高程序的执行速度。需要注意的是,内联函数并不总是能提高性能,因为插入的代码可能会增加可执行文件的大小。因此,内联函数通常用于函数体较小且频繁调用的情况。

  6. 灵活的结构体成员:允许结构体的最后一个成员具有可变长度。

  7. restrict 关键字:用于指针,表示该指针是访问其指向对象的唯一方式。

  8. long long 类型:引入了 long long 类型,提供更大的整数范围。

  9. 复数类型:引入了 _Complex_Imaginary 类型,用于处理复数。

  10. stdint.hinttypes.h 头文件:提供了固定宽度的整数类型和相应的格式化宏。

  11. 预处理器改进:包括 _Pragma 操作符和 __func__ 预定义标识符。

  12. 浮点环境访问:允许程序访问浮点环境的状态。

  13. va_copy:用于复制可变参数列表。

  14. __STDC_VERSION__:用于检测编译器是否支持 C99 标准。

这些特性使得 C99 在功能和灵活性上有了显著的提升。

示例代码

  1. _Bool 类型

    #include <stdio.h>
    int main() {
        _Bool b = 1;
        if (b) {
            printf("b is true\n");
        } else {
            printf("b is false\n");
        }
        return 0;
    }
    

    这里,b 是一个 _Bool 类型的变量,可以赋值为 truefalse

  2. stdbool.h 头文件

    #include <stdio.h>
    #include <stdbool.h>
    int main() {
        bool b = true;
        if (b) {
            printf("b is true\n");
        } else {
            printf("b is false\n");
        }
        return 0;
    }
    
  3. 变长数组(VLA)

    #include <stdio.h>
    void printArray(int n) {
        int array[n];
        for (int i = 0; i < n; i++) {
            array[i] = i;
            printf("%d ", array[i]);
        }
        printf("\n");
    }
    int main() {
        printArray(5);
        return 0;
    }
    

    这里,printArray 函数接受一个整数参数 n,并打印从 0 到 n-1 的数组元素。但是,n 的值在运行时确定,因此数组的大小也会随之变化。因此变长数组又称为for循化初始化。

  4. 复合字面量

    #include <stdio.h>
    struct Point {
        int x, y;
    };
    void printPoint(struct Point p) {
        printf("Point: (%d, %d)\n", p.x, p.y);
    }
    int main() {
        printPoint((struct Point){3, 4});
        return 0;
    }
    

    即可以使用(struct Point){3, 4}来创建结构体对象,也可以使用(int[]){1, 2, 3}来创建数组对象。

  5. 内联函数

    #include <stdio.h>
    //GCC要求内联函数在调用之前必须有声明
    int square(int x);
    inline int square(int x) {
        return x * x;
    }
    int main() {
        printf("Square of 5 is %d\n", square(5));
        return 0;
    }
    
  6. 灵活的结构体成员

    #include <stdio.h>
    #include <stdlib.h>
    struct FlexArray {
        int count;
        int array[];
    };
    int main() {
        struct FlexArray *fa = malloc(sizeof(struct FlexArray) + 5 * sizeof(int));
        fa->count = 5;
        for (int i = 0; i < fa->count; i++) {
            fa->array[i] = i;
            printf("%d ", fa->array[i]);
        }
        printf("\n");
        free(fa);
        return 0;
    }
    
  7. restrict 关键字

    #include <stdio.h>
    void copy(int *restrict dest, const int *restrict src, int n) {
        for (int i = 0; i < n; i++) {
            dest[i] = src[i];
        }
    }
    int main() {
        int src[] = {1, 2, 3, 4, 5};
        int dest[5];
        copy(dest, src, 5);
        for (int i = 0; i < 5; i++) {
            printf("%d ", dest[i]);
        }
        printf("\n");
        return 0;
    }
    

这里,dest 和 src 都被声明为 restrict,这意味着编译器可以假设在 copy 函数执行期间,dest 和 src 指向的内存区域不会通过其他指针被修改。这为编译器提供了优化循环内部代码的机会,例如展开循环或使用更高效的寄存器分配策略。

需要注意的是,restrict 关键字只是一个编译器提示,程序员有责任确保通过 restrict 修饰的指针确实是唯一的访问路径。如果违反了这个假设,可能会导致未定义行为。

  1. long long 类型

    #include <stdio.h>
    int main() {
        long long ll = 123456789012345LL;
        printf("Long long value: %lld\n", ll);
        return 0;
    }
    
  2. 复数类型

    #include <stdio.h>
    #include <complex.h>
    int main() {
        double complex z = 1.0 + 2.0 * I;
        printf("Complex number: %f + %fi\n", creal(z), cimag(z));
        return 0;
    }
    
  3. stdint.hinttypes.h 头文件

    #include <stdio.h>
    #include <stdint.h>
    #include <inttypes.h>
    int main() {
        int32_t x = 123456789;
        printf("int32_t value: %" PRId32 "\n", x);
        return 0;
    }
    
  4. 预处理器改进

    #include <stdio.h>
    #define PRINT_FUNC() printf("Function: %s\n", __func__)
    void myFunction() {
        PRINT_FUNC();
    }
    int main() {
        myFunction();
        return 0;
    }
    

    详细见C99_Preprocessor_Improvements

  5. 浮点环境访问

    #include <stdio.h>
    #include <fenv.h>
      
    // 主函数,程序的入口点
    int main() {
        // 启用标准C环境访问
        #pragma STDC FENV_ACCESS ON
        // 清除所有浮点异常
        feclearexcept(FE_ALL_EXCEPT);
        // 定义一个双精度浮点数并进行除以零的操作
        double a = 1.0 / 0.0;
        // 检查是否发生了除以零的异常
        if (fetestexcept(FE_DIVBYZERO)) {
            // 如果发生了除以零的异常,打印提示信息
            printf("Division by zero occurred\n");
        }
        // 返回0,表示程序正常结束
        return 0;
    }
    

    详细见C99_Floating_Point_Environment

  6. va_copy

    #include <stdio.h>
    #include <stdarg.h>
    
      
    // 可变参数函数,打印所有传入的整数参数
    void printArgs(int count, ...) {
        va_list args, args_copy; // 定义两个va_list类型的变量,用于处理可变参数
        va_start(args, count); // 初始化args,使其指向第一个可变参数
        va_copy(args_copy, args); // 复制args到args_copy
        for (int i = 0; i < count; i++) { // 遍历所有可变参数
            printf("%d ", va_arg(args_copy, int)); // 打印当前参数的值
        }
        printf("\n"); // 打印换行符
        va_end(args); // 清理args
        va_end(args_copy); // 清理args_copy
    }
      
    // 主函数,程序入口
    int main() {
        printArgs(3, 1, 2, 3); // 调用printArgs函数,传入三个参数
        return 0; // 返回0,表示程序正常结束
    }
    
  7. __STDC_VERSION__

    #include <stdio.h>
    int main() {
        #ifdef __STDC_VERSION__
        printf("C Standard version: %ld\n", __STDC_VERSION__);
        #else
        printf("C Standard version not defined\n");
        #endif
        return 0;
    }
    

这些示例展示了 C99 标准中引入的一些主要特性。

C99 标准是在 1999 年更新的。这个标准是对 C 语言的一次重要更新,引入了许多新的特性和改进,以增强语言的功能和灵活性。

文末

参考文献

  1. ISO/IEC 9899:1999 - Programming languages — C. International Organization for Standardization, 1999.
  2. ISO/IEC 9899:2011 - Programming languages — C. International Organization for Standardization, 2011.
  3. ISO/IEC 9899:2018 - Programming languages — C. International Organization for Standardization, 2018.

推荐阅读

  1. 书籍

    • Kernighan, B. W., & Ritchie, D. M. (1988). The C Programming Language (2nd ed.). Prentice Hall.
    • King, K. N. (2008). C Programming: A Modern Approach (2nd ed.). W. W. Norton & Company.
    • Prata, S. (2004). C Primer Plus (5th ed.). Sams Publishing.
    • van der Linden, P. (1994). Expert C Programming: Deep C Secrets. Prentice Hall.
  2. 在线资源

标签:main,return,int,C99,特性,版本,printf,include
From: https://blog.csdn.net/AM72867829/article/details/140697433

相关文章

  • 最新nacos下载安装,版本号2.4.0,nacos持久化存储到本地mysql中,nacos配置登录账户密码
    官网:https://nacos.io/zh-cn/docs/quickstart/quick-start1.下载地址:https://github.com/alibaba/nacos/releases网络不好,很难下载。直接使用git克隆,然后自己编译,这是最快的了。克隆:gitclonehttps://github.com/alibaba/nacos.git然后到根目录中(我的:E:\Demos\nacos),执行cmd命令:mv......
  • 达梦数据库系列—32.多版本并发控制MVCC
            在多版本控制以前,数据库仅通过锁机制来实现并发控制。数据库对读操作上共享锁,写操作上排他锁,这种锁机制虽然解决了并发问题,但影响了并发性。        DM数据库基于物理记录和回滚记录实现行级多版本支持,数据页中只保留物理记录的最新版本,通过回滚记录......
  • 深入探讨PHP8的新特性与性能优化
    本文由ChatMoney团队出品随着互联网技术的飞速发展,PHP作为后端开发领域的热门语言也在不断演进。近期,PHP8的发布引起了广泛关注。本文将为您详细介绍PHP8的新特性以及性能优化,并通过具体示例帮助您更好地理解和应用这些新特性。一、PHP8的新特性示例联合类型(UnionTypes)......
  • DolphinPHP1.5.1版本的RCE
    侵权声明本文章中的所有内容(包括但不限于文字、图像和其他媒体)仅供教育和参考目的。如果在本文章中使用了任何受版权保护的材料,我们满怀敬意地承认该内容的版权归原作者所有。如果您是版权持有人,并且认为您的作品被侵犯,请通过以下方式与我们联系:[[email protected]]。我们将在确......
  • Jupyter Notebook 环境中的 Python 版本不匹配
    我遇到Jupyter笔记本启动横幅中报告的Python版本与我在笔记本中查询python--version时显示的版本之间的差异。启动横幅指示Python3.11.9,但是当我运行!python--version时,它返回Python3.11.7。我所做的步骤:basecondahas3.11.7versio......
  • 深入理解 Java17 新特性:Sealed Classes
    0关键总结JavaSE15在2020年9月发布,预览功能引入“封闭类”(JEP360)封闭类是一种限制哪些其他类或接口可扩展它的类或接口类似枚举,封闭类在领域模型中捕获替代方案,允许程序员和编译器推理其穷尽性封闭类对于创建安全的层次结构也很有用,通过解耦可访问性和可扩展性,允许库开......
  • 软件版本号为什么那么奇怪?
    语义版本管理提供了一种清晰、结构化的软件版本管理方法,让开发人员更容易了解变更的影响并管理依赖关系。通过遵循SemVer规则,开发人员可以确保其软件以可预测的方式稳定发展。软件版本号意味着什么?语义版本管理(SemVer)是一种软件版本管理方案,旨在传达版本中基本变更的含义。......
  • MySQL8新特性底层原理
    降序索引什么是降序索引MySQL8.0开始真正支持降序索引(descendingindex)。只有InnoDB存储引擎支持降序索引,只支持BTREE降序索引。另外MySQL8.0不再对GROUPBY操作进行隐式排序。在MySQL中创建一个t2表 createtablet2(c1int,c2int,indexidx1(c1asc,c2desc)); ......
  • centos 更新curl版本
    HowtoBuildandInstallLatestcURLVersiononCentOS#WrittenbyTheSuhu(2021).#TestedonCentOS7andCentOS8PreviouslyI'vewrittenabout HowtoBuildandInstallLatestcURLVersiononUbuntu.Inthisarticleinthisarticleexplainho......
  • Centos7下安装配置最新版本Jenkins(2.452.3)
    1、基础环境配置1.1服务器下载Jenkins安装包下载地址:https://www.jenkins.io/download/下载命令:wgethttps://get.jenkins.io/war-stable/2.452.3/jenkins.war1.2服务器安装配置JDKJenkins是基于Java语言开发的,因此需要Java运行环境支持。安装JDK前一定要看下当前要......