【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 风格格式检查 |

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

相关推荐
BackCatK Chen1 小时前
第 1 篇:软件视角扫盲|TMC2240 软件核心特性 + 学习路径(附工具清单)
c语言·stm32·单片机·学习·电机驱动·保姆级教程·tmc2240
梵刹古音2 小时前
【C语言】 格式控制符与输入输出函数
c语言·开发语言·嵌入式
VekiSon2 小时前
Linux内核驱动——基础概念与开发环境搭建
linux·运维·服务器·c语言·arm开发
无限进步_2 小时前
面试题 02.02. 返回倒数第 k 个节点 - 题解与详细分析
c语言·开发语言·数据结构·git·链表·github·visual studio
Hello World . .2 小时前
数据结构:栈和队列
c语言·开发语言·数据结构·vim
zhangx1234_4 小时前
C语言 数据在内存中的存储
c语言·开发语言
嵌入小生0075 小时前
双向链表、双向循环链表之间的异同---嵌入式入门---Linux
linux·c语言·数据结构·链表·嵌入式·小白
BoJerry7775 小时前
数据结构——单链表(不带头)【C】
c语言·开发语言·数据结构
进击的小头6 小时前
设计模式组合应用:智能硬件控制系统
c语言·设计模式
EmbedLinX6 小时前
FreeRTOS 学习笔记
c语言·笔记·学习