我想知道scanf函数是如何实现的。(当然只是为了好玩)参数的数量是可变的,所以它肯定是由va_list
、va_arg
宏实现的。
当参数的数量和格式字符串不匹配时,它还会抛出一些警告。这可以通过解析格式字符串并将其与参数数量进行比较来完成。没有魔法。
我唯一看不到如何实现的是类型检查。当参数的类型(指向数据的指针)和格式文字中相应的声明不匹配时,scanf
会产生警告。如何检查指针指向的数据类型?
示例:
#include<stdio.h>
int main()
{
char buffer1[32], buffer2[32];
int n;
double x;
scanf("%s %s %d",buffer1, buffer2, &x); // warning
scanf("%s %s %d",buffer1, buffer2, &n); // ok
}
输出:
warning: format ‘%d’ expects argument of type ‘int *’,
but argument 4 has type ‘double *’ [-Wformat]
AFAIK C库不是C语言/编译器的一部分,因此<stdio.h>
中没有任何与语言相关的内容。我假设警告是由scanf
的实现产生的,而不是由编译器[?]产生的。(可能使用#warning
)
如果我想在某些代码中做类似的事情,我如何知道指针指向的是哪种数据类型?
注意:我已经下载了GNU C库的源代码,并查看了scanf.c
。我在这个非常复杂的代码中找不到路。有很多#ifndef
和对其他具有奇怪名称和结构的函数的调用。。。
此检查由gcc编译器处理,特别是针对scanf/printf函数。
这是一个常见的错误,因此值得为这些函数的编译器添加特殊情况代码。
请参阅此处的GCC-WFormat标志:http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Warning-Options.html
-Wformat:检查对printf和scanf等的调用,以确保提供的参数具有适合格式字符串的类型指定,并且格式字符串中指定的转换说得通。这包括标准功能,以及格式化属性(请参见函数属性),在printf、scanf、,strftime和strfmon(X/Open扩展,不在C标准中)家庭。
这些检查并不是所有编译器都能实现的,所以它肯定不是可以依赖的。
使用GCC,您可以使用函数属性"format"one_answers"format arg"来告诉编译器对您的函数应用相同的检查。
format(原型,字符串索引,第一个检查)format属性指定函数采用printf、scanf、strftime或strfmon样式参数,应该根据格式字符串进行类型检查。例如,声明:
extern int my_printf (void *my_object, const char *my_format, ...)
__attribute__ ((format (printf, 2, 3)));
。。。使编译器检查my_printf调用中的参数是否与printf样式的格式字符串参数一致my_format。
警告由编译器生成。您将x
声明为double
,因此它知道&x
是double*
。然后,它扫描格式字符串,发现该格式需要int*
,因此发出警告。