__attribute__((format(printf, 2, 3)))用法详解

_attribute_((format(printf, 2, 3)))用法详解

在阅读redis源码的时候,遇到_attribute_((format(printf, 2, 3)))用法,在此记录下该用法的作用以及需要注意的点。

1. 用法及作用

​ 在C语言编程过程中,我们常常会实现一些可变参数的函数调用(类scanf、printf函数),变参函数在我们编程过程中带来了很大的方便,但是也有一些问题,即我们在调用可变参数的函数的时候,默认情况下编译器检查不出可变参数的类型或者个数是否正确,这就导致使用变参函数的时候,若稍不注意写错了参数,很难被发现和定位。

​ _attribute_((format(printf, 2, 3)))的作用就是用来解决这个问题,它用于函数声明,作用是提示编译器检查函数调用的过程中,可变参数部分按照printf的规则进行检查,若参数的个数或者类型不匹配,编译过程中将会发出警告,这就使得上面提到的问题在编译期间就能发现。注意编译时要加上 –Wall才可以。

// 用法原型
// archetype:为按照那种风格进行校验,如printf/scanf等
// string-index:格式化format字符串所在的位置,如void test(testA, format,...),此时为2
// first-to-check:第一个可变参数的位置,如void test(testA, format,...),此时为3
__attribute__((format(archetype, string-index, first-to-check)))

注意:string-index和first-to-check值选取的时候,若变参函数是类成员函数,这时函数展开后第一个参数为this指针,这个也要考虑到位置中。

2.使用示例

2.1 普通函数使用示例

在普通函数中,string-index和first-to-check参数值即为实际的位置,如下面的测试样例string-index=1,first-to-check=2

// test_format.cpp
#include <iostream>
#include <stdarg.h>
#include <stdint.h>

void test(const char* format, ...) __attribute__((format(printf, 1, 2)));
void test(const char* format, ...)
{
	 va_list ap;
	 std::string str;
	 while (true)
	 {
	 	char* buffer = new char[1024];
	 	va_start(ap, format);
		int expected = vsnprintf(buffer, 1024, format, ap);
		va_end(ap);
		str += std::string(buffer);
		if (expected > -1 && expected < 1024)
			break;
	 }

	 std::cout << "result:" << str << std::endl;;
}

int main()
{
	std::string s = "123%s%d%s%s%s%s%s%0d";
	test("%s%d",s.c_str());
}

上述测试样例的编译结果如下:

g++ test_format.cpp -Wall
test_format.cpp: In function ‘int main()’:
test_format.cpp:27: warning: too few arguments for format

如去掉__attribute__((format(printf, 1, 2))); 修饰编译结果将没有warning,可去掉自行测试。

2.2 类成员函数使用示例

在类成员函数中,string-index和first-to-check参数值要比实际的位置向后移动一位,因为类成员函数展开后第一个参数为this指针,如下面的测试样例string-index=2,first-to-check=3

// class_test_format.cpp
#include <iostream>
#include <stdarg.h>
#include <stdint.h>
#include <string>

class Test
{
	public:
		void test(const char* format, ...) __attribute__((format(printf, 2, 3)));
};

void Test::test(const char* format, ...)
{
	va_list ap;
	 std::string str;
	 while (true)
	 {
	 	char* buffer = new char[1024];
	 	va_start(ap, format);
		int expected = vsnprintf(buffer, 1024, format, ap);
		va_end(ap);
		str += std::string(buffer);
		if (expected > -1 && expected < 1024)
			break;
	 }

	 std::cout << "result:" << str << std::endl;;
}

int main()
{
	std::string s = "123%s%d%s%s%s%s%s%0d";
	Test t;
	t.test("%s%d",s.c_str());
}

上述测试样例的编译结果如下:

g++ class_test_format.cpp -Wall
class_test_format.cpp: In function ‘int main()’:
class_test_format.cpp:34: warning: too few arguments for format

如去掉__attribute__((format(printf, 2, 3))); 修饰编译结果将没有warning,可去掉自行测试。

发布了130 篇原创文章 · 获赞 40 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/u014630623/article/details/101107023
今日推荐