【C】利用GCC扩展属性进行格式化字符串的静态检查

一、问题引入

在项目实践中,时常发生自定义的格式化输入输出函数中,因为打印格式与参数类型不匹配导致的故障。典型的问题有:

  • 格式化输出使用%s打印一个整型,导致进程跑飞
  • 格式化输出使用%d打印一个长整型,导致打印数据截断
  • 格式化输出格式符多于实际参数个数,导致进程跑飞
  • 格式化输入使用%u打印一个 unsigned char 或 unsigned short 类型整型,导致踩内存

下面,借助 GCC 编译器的__attribute__((format(...))) 扩展属性,用于在编译时进行格式字符串的静态检查,提前发现问题。

示例

cpp 复制代码
int ios_snprintf_s(char * restrict s, rsize_t n, const char *restrict format, ...) __attribute__((format(printf, 3, 4)))

二、示例详解

1. 格式字符串检查

  • format: 指定这是一个格式字符串函数
  • printf: 指定使用 printf 系列的格式规则进行检查
  • 3, 4: 指定参数位置
  • 第3个参数是格式字符串位置 (即const char *restrict format)
  • 第4个参数是可变参数列表的开始位置 (...)

2. 编译时检查

编译器会在编译时检查:

cpp 复制代码
// 示例用法
char buf[100];
ios_snprintf_s(buf, sizeof(buf), "Name: %s, Age: %d", name, age);

// 如果格式字符串与参数不匹配,编译时会报警告
ios_snprintf_s(buf, sizeof(buf), "Name: %s, Age: %d", name); 
// 警告:参数数量不足
  1. 实际效果
cpp 复制代码
// 正确的使用 - 无警告
ios_snprintf_s(buffer, size, "Hello %s!", name);

// 错误的使用 - 编译警告
ios_snprintf_s(buffer, size, "Hello %s!", 123);
// 警告:格式 '%s' 需要 'char*' 但参数是 'int'

ios_snprintf_s(buffer, size, "Value: %d");
// 警告:格式 '%d' 缺少对应参数

三、类似属性

|------------------------|-----------------|
| 属性 | 用途 |
| format(printf, n, m) | printf 风格格式检查 |
| format(scanf, n, m) | scanf 风格格式检查 |
| format(strftime, n, m) | strftime 风格格式检查 |

这种属性在项目安全编码中特别有用,可以提前发现格式化字符串相关的潜在错误。

相关推荐
Herbert_hwt25 分钟前
C语言循环结构完全指南:掌握for、while、do-while循环及实战应用
c语言
奔跑吧邓邓子44 分钟前
【C语言实战(79)】深入C语言单元测试:基于CUnit框架的实战指南
c语言·单元测试·实战·cunit
Shylock_Mister1 小时前
弱函数:嵌入式回调的最佳实践
c语言·单片机·嵌入式硬件·物联网
攒钱植发2 小时前
嵌入式Linux——“大扳手”与“小螺丝”:为什么不该用信号量(Semaphore)去模拟“完成量”(Completion)
linux·服务器·c语言
三品吉他手会点灯2 小时前
STM32F103学习笔记-16-RCC(第3节)-使用HSE配置系统时钟并使用MCO输出监控系统时钟
c语言·笔记·stm32·单片机·嵌入式硬件·学习
jzhwolp3 小时前
从nginx角度看数据读写,阻塞和非阻塞
c语言·nginx·性能优化
oioihoii6 小时前
《C语言点滴》——笑着入门,扎实成长
c语言·开发语言
say_fall8 小时前
C语言容易忽略的小知识点(1)
c语言·开发语言
程序员东岸11 小时前
数据结构精讲:从栈的定义到链式实现,再到LeetCode实战
c语言·数据结构·leetcode
say_fall11 小时前
C语言容易被忽略的易错点(2)
c语言·开发语言