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

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

相关推荐
LDR0062 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
Luminous.2 天前
C语言--day30
c语言·开发语言
玖玥拾2 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
謓泽2 天前
C语言不是语法,是通往机器的地图。
c语言·开发语言
不会C语言的男孩2 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言
2601_951643882 天前
C语言长文整理,关键字和数据类型
c语言·数据类型·关键字·嵌入式开发·格式化输出
m0_547486662 天前
《C#语言程序设计与实践》 全套PPT课件
c语言·c#·c语言程序设计
✎ ﹏梦醒͜ღ҉繁华落℘2 天前
编程基础 --高内聚,低耦合
c语言·单片机
QK_002 天前
C语言 static 关键字三大作用
c语言·开发语言
隔窗听雨眠2 天前
C语言函数递归从入门到精通(下):性能优化与工程实践
c语言·算法·性能优化