• 通过例子学C标准库<assert.h>


    简介


    C 标准库的 assert.h头文件提供了一个名为 assert 的宏,它可用于验证程序做出的假设,并在假设为假时输出诊断消息。

    已定义的宏 assert 指向另一个宏 NDEBUG,宏 NDEBUG 不是 的一部分。如果已在引用 的源文件中定义 NDEBUG 为宏名称,则 assert 宏的定义如下:

    #define assert(ignore) ((void)0)

    宏里面这样用的目的是防止该宏被用作右值, 因为 void 类型不能用作右值,还有的伙伴可能疑惑,那干嘛不直接用 void,那是因为在编译程序时,首先会预编译程序,把相关的头文件包含进来,并把文件中定义的宏进行替换,直接用 void 的话,预编译时该宏被替换成 void; 这句代码,在编译时编译器会 警告:空声明中类型名无用

    库宏
    下面列出了头文件 assert.h 中定义的唯一的函数:

    序号函数&描述
    1void assert(int expression) // 这实际上是一个,不是一个函数,可用于在 C 程序中添加诊断。
    expression:如果 expression 为 非0,assert() 不执行任何动作。如果 expression 为 0,assert() 会在标准错误 stderr 上显示错误消息,并中止程序执行。

    下面的例子验证:
    不能直接用 void 替换 (void)0,预编译程序时宏被替换成 void; 这句代码,在编译时编译器会 警告:空声明中类型名无用

    assert_example_user_macro.c 文件

    #include 
    
    #define user_macro(age) void
    
    int main()
    {
        int age = 20;
        user_macro(age);
    
        printf("age = %d\n", age);
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    gcc -o assert_example_user_macro.i -E assert_example_user_macro.c // -E 告诉编译器,对 assert_example_user_macro.c 文件进行预编译,并生成预编译文件 assert_example_user_macro.i

    assert_example_user_macro.i 文件截图
    在这里插入图片描述

    gcc -o assert_example_user_macro assert_example_user_macro.c

    在这里插入图片描述

    下面的例子验证:
    已定义的宏 assert 指向另一个宏 NDEBUG,宏 NDEBUG 不是 的一部分。如果已在引用 的源文件中定义 NDEBUG 为宏名称,则 assert 宏的定义为:#define assert(ignore) ((void)0)

    assert_example_release.c 文件

    #define NDEBUG 1 // 定义了NDEBUG
    
    #include 
    #include 
    #include 
    
    char *str_cpy(char *des, const char *src);
    
    int main()
    {
        char *p = NULL;
        char src[] = "Jim is a student.";
        p = (char *)malloc(sizeof(src)/sizeof(*src));
        str_cpy(p, src);
        printf("%s\n", p);
        free(p);
    
        return 0;
    }
    
    char *str_cpy(char *des, const char *src)
    {
        assert(des);
        assert(src);
        char *p = des;
        while((*p++ = *src++) != '\0');
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    gcc -o assert_example_release.i -E assert_example_release.c // -E 告诉编译器,对 assert_example_release.c 文件进行预编译,并生成预编译文件 assert_example_release.i

    assert_example_release.i 文件截图
    在这里插入图片描述

    通过上面的例子也可以证明assert可能被预处理过程被替换成 (void)0,当使用这个宏的时候必须保证条件表达式不存在别的作用。特别的,不应该在assert的条件表达式中使用这些语句:函数调用、对变量赋值、使用修改变量的操作符(如 ++ 等)。不然可能导致一个程序在Release版本下编译出来的可执行文件执行的结果跟Debug版本不一样。

    使用例子

    assert_example.c 文件

    #include 
    #include 
    #include 
    
    char *str_cpy(char *des, const char *src);
    
    int main()
    {
        char *p = NULL;
        char src[] = "Jim is a student.";
        //p = (char *)malloc(sizeof(src)/sizeof(*src));
        str_cpy(p, src);  // 这里由于传入的 p = NULL,所以assert() 会在标准错误 stderr 上显示错误消息,并中止程序执行。
        printf("%s\n", p);
        free(p);
    
        return 0;
    }
    
    char *str_cpy(char *des, const char *src)
    {
        assert(des);
        assert(src);
        char *p = des;
        while((*p++ = *src++) != '\0');
    
        return des; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    gcc -o assert_example.i -E assert_example.c // -E 告诉编译器,对 assert_example.c 文件进行预编译,并生成预编译文件 assert_example.i

    assert_example.i 文件截图
    在这里插入图片描述

    可执行文件执行结果
    在这里插入图片描述

  • 相关阅读:
    TIA博途V17中ProDiag功能的使用方法示例(一)PLC数据类型的监控
    云原生之深入解析Prometheus Pushgetway的原理分析和实战操作
    Windows Server 2019 激活
    Netty网络框架学习笔记-15(ChannelPipeline 调度 handler分析)
    软件工程第三周
    23、短信登录(基于redis实现共享session登录)
    IDA* AcWing 181. 回转游戏
    数据仓库之雪花模型
    数据湖iceberg-day01-概念,特点,存储格式以及各种表中的演化,数据类型
    视频播放VideoView
  • 原文地址:https://blog.csdn.net/d704791892/article/details/125874968