You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C语言中自定义assert()的错误提示消息并替换默认输出?

自定义断言失败输出的问题修正

需求说明

期望断言失败时输出如下格式的提示:

Assertion failed!
Program: C:\...\assert-test.exe
File: C:\...\assert-test.c, Line 21
Expression: denominator != 0.0

尝试通过定义NDEBUG禁用默认assert并自定义断言逻辑,但原有代码存在多处错误,导致无法达到预期效果,以下是问题分析和修正方案:

原代码的核心问题

  1. 宏逻辑完全颠倒:NDEBUG的作用是禁用断言,原代码却在定义NDEBUG时启用自定义断言,未定义时反而空实现,完全搞反了逻辑。
  2. 参数传递错误:M_Assert宏中传递的buffer是未定义变量,__M_Assert函数无法直接使用。
  3. C/C++语法混用:使用了C++的std::cerr,但代码整体是C风格,应该用C标准库的错误输出方式。
  4. Windows API依赖缺失:调用GetModuleFileName但未包含windows.h,MAX_PATH也未定义。
  5. 断言逻辑错误:__M_Assert中判断的是表达式字符串是否为空,而非断言表达式的真假。
  6. 语法错误:主函数return后无返回值,宏定义末尾多余分号。

修正后的完整代码

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>  // 包含Windows API所需头文件

// 处理scanf的跨平台定义
#if defined(_STDC_LIB_EXT1_) || defined(_MSC_VER)
    #define __STDC_WANT_LIB_EXT1_ 1
    #define SCANF scanf_s
#else
    #define SCANF scanf
#endif

// 自定义断言宏:未定义NDEBUG时启用,定义时禁用
#ifndef NDEBUG
    #define M_Assert(expr) \
        do { \
            if (!(expr)) { \
                char buffer[MAX_PATH]; \
                GetModuleFileName(NULL, buffer, MAX_PATH); \
                __M_Assert(buffer, __FILE__, __LINE__, #expr); \
            } \
        } while(0)
#else
    #define M_Assert(expr) ((void)0)  // 空实现,避免语法问题
#endif

// 自定义断言输出函数
void __M_Assert(const char* program_path, const char* file, int line, const char* expr) {
    fprintf(stderr, "Assertion failed!\n");
    fprintf(stderr, "Program: %s\n", program_path);
    fprintf(stderr, "File: %s, Line %d\n", file, line);
    fprintf(stderr, "Expression: %s\n", expr);
    abort();  // 终止程序
}

int main() {
    double numerator = 0.0, denominator = 0.0;
    printf("--- Quotient of two numbers ---\nEnter the nominator: ");
    if (SCANF("%lf", &numerator) < 1) {
        fprintf(stderr, "invalid input\n");
        return 1;
    }
    printf("denominator: ");
    if(SCANF("%lf", &denominator) < 1) {
        fprintf(stderr, "invalid input\n");
        return 1;
    }

    M_Assert(denominator != 0.0);  // 调用自定义断言

    printf("quotient is %f\n", numerator / denominator);
    return 0;  // 补充返回值
}

关键修正点说明

  • 宏逻辑修正:用#ifndef NDEBUG判断,只有在调试模式(未定义NDEBUG)时才启用自定义断言,发布模式下自动禁用。
  • 表达式判断:在宏内先计算expr的真假,为假时才调用输出函数,符合断言的核心逻辑。
  • 缓冲区处理:在宏内定义buffer局部变量,传递给函数,避免未定义变量问题。
  • 纯C输出:用fprintf(stderr, ...)替代C++的std::cerr,符合C语言规范。
  • 依赖补充:添加windows.h以使用GetModuleFileName和MAX_PATH。
  • 语法修复:去掉宏定义末尾的多余分号,补充主函数的返回值0。

使用说明

  • 调试编译时,不要定义NDEBUG宏,此时断言会生效,失败时输出自定义格式。
  • 发布编译时,添加-DNDEBUG(GCC/Clang)或在项目设置中定义NDEBUG(MSVC),断言会被完全移除,不影响程序性能。

内容的提问来源于stack exchange,提问作者Assel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 22:47:32