断言子系统(CategoryAssert)
SDL 提供的增强型断言宏,功能远超常规的 assert 宏,核心特性如下:
- 利用
sizeof运算符特性:禁用的断言会从编译代码中完全移除,且仅在断言中引用的变量不会触发“未使用变量”的编译器警告; - 避免悬空 else 问题:支持
if (x) SDL_assert(y); else do_something();这类写法,行为稳定; - 跨平台一致性:不依赖各平台编译器/C 运行时的实现,所有平台行为统一;
- 多级别断言:提供
SDL_assert、SDL_assert_release、SDL_assert_paranoid等不同级别,而非“全有或全无”的单一选项; - 丰富的失败响应:断言失败时支持重试、触发调试器、终止程序、单次忽略、永久忽略等操作;
- 可视化提示:默认尝试弹出对话框提示用户(若平台支持),也可自定义回调函数处理断言失败;
- 重试机制:断言失败后可重试(比如网络故障修复后重新验证条件);
- 忽略选项:支持单次忽略或永久忽略某类无害的断言失败;
- 统计能力:向应用程序提供所有断言失败的统计数据和详细信息;
- 环境变量控制:自动化脚本可通过环境变量控制默认断言处理器行为;
- 静态分析友好:Clang 静态分析会将 SDL 断言视为“恒真”(假设调试构建能检测断言错误),减少误报。
使用方式:编译调试版本时,在代码中按需添加断言检测逻辑即可!
函数
- SDL_GetAssertionHandler:获取当前设置的自定义断言处理函数
- SDL_GetAssertionReport:获取所有断言失败的报告(返回 SDL_AssertData 链表)
- SDL_GetDefaultAssertionHandler:获取 SDL 默认的断言处理函数
- SDL_ReportAssertion:手动触发断言报告(底层接口,一般无需直接调用)
- SDL_ResetAssertionReport:清空所有断言失败的报告数据
- SDL_SetAssertionHandler:设置自定义的断言失败处理函数(替换默认逻辑)
数据类型
- SDL_AssertionHandler:断言处理函数的函数指针类型(自定义断言处理时需实现)
结构体
- SDL_AssertData:存储单个断言失败的详细信息(断言表达式、文件、行号、失败次数等)
枚举
- SDL_AssertState:定义断言失败后的处理状态(重试、终止、单次忽略、永久忽略等)
宏
- SDL_assert:基础断言宏(调试版本启用,发布版本禁用)
- SDL_assert_always:强制启用的断言(无论编译模式,始终生效)
- SDL_ASSERT_FILE:获取断言所在文件路径(内部宏)
- SDL_ASSERT_LEVEL:定义断言启用级别(控制不同级别断言是否生效)
- SDL_assert_paranoid:偏执级断言(仅在开启极致调试时启用,用于细粒度检测)
- SDL_assert_release:发布版本断言(仅在发布版本中启用,检测严重问题)
- SDL_AssertBreakpoint:触发调试器断点(断言失败时调用)
- SDL_disabled_assert:禁用断言的占位宏(编译时会被移除)
- SDL_enabled_assert:启用断言的核心宏(内部实现)
- SDL_FILE:等价于 FILE,获取当前文件路径
- SDL_FUNCTION:等价于 func,获取当前函数名
- SDL_LINE:等价于 LINE,获取当前行号
- SDL_NULL_WHILE_LOOP_CONDITION:检测 while 循环条件为 NULL 的断言(专用宏)
- SDL_TriggerBreakpoint:同 SDL_AssertBreakpoint,触发调试断点
FreeBASIC 示例代码
' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL 库)
#Include "SDL.bi"
' 自定义断言处理函数示例
Function CustomAssertHandler Cdecl (ByVal data As SDL_AssertData Ptr, ByVal userdata As Any Ptr) As SDL_AssertState
' 打印断言失败详情
SDL_LogError(SDL_LOG_CATEGORY_ASSERT, "断言失败:")
SDL_LogError(SDL_LOG_CATEGORY_ASSERT, " 文件:%s", data->file)
SDL_LogError(SDL_LOG_CATEGORY_ASSERT, " 行号:%d", data->line)
SDL_LogError(SDL_LOG_CATEGORY_ASSERT, " 函数:%s", data->function_)
SDL_LogError(SDL_LOG_CATEGORY_ASSERT, " 表达式:%s", data->condition)
SDL_LogError(SDL_LOG_CATEGORY_ASSERT, " 失败次数:%d", data->trigger_count)
' 这里返回“重试”,也可根据需求返回 SDL_ASSERT_ABORT/SDL_ASSERT_IGNORE 等
Return SDL_ASSERT_RETRY
End Function
' 主程序示例
Dim As Integer testValue = -1
' 设置自定义断言处理器
SDL_SetAssertionHandler(@CustomAssertHandler, NULL)
' 示例1:基础断言(调试模式生效)
SDL_assert(testValue > 0) ' testValue=-1,断言失败
' 示例2:始终生效的断言
SDL_assert_always(testValue <> 0) ' 即使发布版本也会触发
' 示例3:发布版本断言(仅在 release 模式生效)
SDL_assert_release(testValue < 100) ' 表达式为真,断言通过
' 示例4:获取并打印断言报告
Dim As SDL_AssertData Ptr report = SDL_GetAssertionReport()
If (report <> NULL) Then
SDL_LogInfo(SDL_LOG_CATEGORY_ASSERT, "断言失败总数:%d", report->trigger_count)
SDL_ResetAssertionReport() ' 清空报告
End If
' 恢复默认断言处理器
SDL_SetAssertionHandler(SDL_GetDefaultAssertionHandler(), NULL)
评论一下?