1 解释

format是GCC提供的众多attribute之一,这个attribute的作用是告知编译器检查传给相应函数的参数中的格式字符串

/* 这是用在声明的情况,用在定义也可以 */
/* 一般全局函数用在声明,这样包含相应头文件并使用该全局函数的源码就会被编译器做相应检查 */
/* 而局部函数就在本文件使用,无需声明,那么这个attribute可以直接用在定义 */
extern int
my_printf(void *my_object, const char *my_format, ...)
__attribute__ ((format(archetype, string-index, first-to-check)));

在这个例子中也就是检查my_format参数。

熟悉c语言的同学应该知道,像printf等函数使用时,有格式字符串参数。格式字符串中使用诸如%d%c这样的格式控制字符来进行指出后续参数的类型以及格式。但是格式控制字符并不是随意指定的,比如printf中%b%j就是不存在的。此外,也不能出现指定了%d,但后面的变参部分却没有传整形参数或传的是其它类型的参数。换句话说,格式字符串是有一定要求的。而且,不同的用到格式字符串的函数对于格式字符串的要求也是不同的,比如strftime函数,该函数的格式字符串中就有%b,表示月份的简写。

假如我想要上例中的my_printf的格式字符串应该和printf的格式字符串风格一致,并希望编译器对此做检查,那么就可以这样使用format属性:

extern int
my_printf(void *my_object, const char *my_format, ...)
__attribute__ ((format(printf, 2, 3)));

现在解释一下archetypestring-indexfirst-to-check的含义:

名称 含义
archetype 检查格式字符串参数和archetype指定的函数的格式字符串风格是否一致
string-index 要检查的格式字符串参数在函数原型中的位置(第几个参数),从1开始算
first-to-check 根据格式字符串去检查的第一个参数的位置,通常就是变参的位置

仍以strftime函数来说,这个函数没有变参部分,像这种或类似的情况,那么first-to-check应该指定为0。此时,编译器仅检查格式字符串的风格,而不会检查变参部分的类型是否相匹配。

2 举例

在linux kernel中就使用到了这个attribute,比如说下面的宏定义:

#define __printf(a, b)                  __attribute__((__format__(printf, a, b)))

kobject.h中,有这样的函数声明:

extern __printf(2, 3)
int kobject_set_name(struct kobject *kobj, const char *name, ...);
extern __printf(2, 0)
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,va_list vargs);

使用format属性可以让编译器多做一些检查,以免我们编程时犯错误。如果一些本来难以察觉的错误能够通过一个属性的使用,使得编译器帮我们检查出来,那么,这对项目的开发是很有益的。

GCC的attribute——format相关推荐

  1. Kernel: GCC_PLUGIN_LATENT_ENTROPY gcc plugin attribute latent_entropy

    文章目录 使用 定义GCC_PLUGIN_LATENT_ENTROPY 实现 系统已有random的实现,非latent_entropy 使用 #ifndef CHECKER #ifdef LATEN ...

  2. GCC中的弱符号与强符号

    转载自 https://www.cnblogs.com/kernel_hcy/archive/2010/01/27/1657411.html 我们经常在编程中碰到一种情况叫符号重复定义.多个目标文件中 ...

  3. 【GCC】gcc警告选项汇总--编辑中|gcc编译选项

    目录 前言 请求或取消警告选项 GCC编译选项 参考原文:https://blog.csdn.net/qq_17308321/article/details/79979514 前言 警告:不是错误的, ...

  4. gcc警告选项汇总 转

    ---------------- 原文链接:https://blog.csdn.net/qq_17308321/article/details/79979514 参考资料:https://gcc.gn ...

  5. 深入剖析 iOS 编译 Clang LLVM(编译流程)

    2019独角兽企业重金招聘Python工程师标准>>> 前言 iOS 开发中 Objective-C 和 Swift 都用的是 Clang / LLVM 来编译的.LLVM是一个模块 ...

  6. 【嵌入式】C语言高级编程-变参函数(08)

    00. 目录 文章目录 00. 目录 01. format属性声明 02. 变参函数的设计思路 03. 变参函数宏 04. 应用示例 05. 附录 01. format属性声明 GNU 通过 attr ...

  7. 深入剖析 iOS 编译 Clang / LLVM

    前言 2000年,伊利诺伊大学厄巴纳-香槟分校(University of Illinois at Urbana-Champaign 简称UIUC)这所享有世界声望的一流公立研究型大学的 Chris ...

  8. pytorch学习笔记(十二):详解 Module 类

    Module 是 pytorch 提供的一个基类,每次我们要 搭建 自己的神经网络的时候都要继承这个类,继承这个类会使得我们 搭建网络的过程变得异常简单. 本文主要关注 Module 类的内部是怎么样 ...

  9. djangorestframework源码分析2:serializer序列化数据的执行流程

    djangorestframework源码分析 本文环境python3.5.2,djangorestframework (3.5.1)系列 djangorestframework源码分析-serial ...

最新文章

  1. java requiredstringvalidator_如何访问自定义组件中的Validator.required
  2. [Spark][翻译]Spark 架构: Shuffle过程分析
  3. 一加7pro保存的录音文件在哪一个文件夹?
  4. JAVA 函数式接口存在
  5. 国产杀毒软件连续因“作弊”遭全球权威评测机构指责
  6. 生产环境Mysql数据库备份脚本
  7. python包的init文件_Python模块包中__init__.py文件的作用
  8. LCD1602的学习与理解
  9. 提供一个在Selenium截网页长图的实现
  10. 计算机专业考研410分,从一个中专生到考研410分的历程
  11. 网络嗅探器(影音神探) v4.63 绿色正式版http://down.hotlife.cn/html/download/2006/6/05/1149478572.shtml
  12. 在 .NET 应用程序中运行 JavaScript
  13. 例13.14 将一组数据保存在字符数组中。
  14. javascript入门实例:实现简单网页功能
  15. idea中摸鱼插件_上班防摸鱼插件(知乎页面)
  16. Word高版本打开低版本显示兼容模式
  17. python批量修改列名_pandas修改DataFrame列名的实现方法
  18. 网络协议--SSL/TLS
  19. java检测服务器磁盘空间占满_Java性能检测工具-记录一次通过jstack排查Linux服务器CPU占用率很高的实践...
  20. 小米平板添加位置服务器,小米平板电脑能定位吗?3种可实现小米平板定位导航的方法介绍_硬件教程...

热门文章

  1. 最大交叉熵matlab实现,交叉熵算法
  2. java实例化字符串两种方式区别
  3. l11.CenterOS6.5升级到7
  4. 从零开始学爬虫系列3:漫画下载,动态加载、反爬虫这都不叫事!
  5. 两人斗地主客户端源码(二)
  6. 文件传输校验-crc32校验算法
  7. osmosis 心电图学习
  8. JMeter安装图文及入门教程
  9. 一、Oracle AQ
  10. Direct UI 思想阐述