【发布时间】:2017-09-27 23:13:32
【问题描述】:
程序:
#ifndef PRINTF_H
#define PRINTF_H
#include "my_put_char.h"
int my_printf(char *str, ...);
#endif
这是我的函数的头文件。
#include <stdio.h>
#include "my_put_char.h"
void my_put_char(char c)
{
fwrite(&c, sizeof(char), 1, stdout);
}
这是我的 putchar 实现(my_put_char.c)。
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "printf.h"
int my_printf(char *str, ...)
{
if(str == NULL)
return 0;
int i;
char a;
va_list print;
va_start(print,str);
for(i = 0; str[i] ; i++)
{
if(str[i] == '%')
{
i++;
switch(str[i])
{
case 'c':
a = va_arg(print, char);
my_put_char(a);
break;
}
}
}
va_end(print);
return 0;
}
最后,这是我的 printf 实现的一部分。
我正在使用%c 进行测试以显示一个字符。
当我从main.c 做my_print("%c", 'd'); 时
它编译并显示d。
但是当我执行 my_print("%c", "hi"); 时,它仍然会编译并显示一个数字。
问题:
写a = va_arg(print, char);之后(或之前)有没有办法检查我的输入是否是不同的数据类型?
如果我的输入是不同的数据类型,我会尝试显示错误。
我在这个主题上研究了 2 天,但找不到任何答案。 非常感谢您的宝贵时间!
【问题讨论】:
-
无法确定类型。看看this。 (它是 cppreference,但在这里无关紧要。)具体来说,它说“如果 ap 中的下一个参数的类型(在提升之后)与 T 不兼容,则行为未定义”。
-
@Yunnosch,感谢您编辑这篇文章!
-
为什么你的
printf.h标头包含my_put_char.h标头?printf.h的用户会使用其中声明的内容吗?注意格式字符串应该是const char *fmt(加上const); C99、C11 和 POSIX 也可以使用restrict(int printf(const char * restrict format, ...);) 对其进行限定。您的实现文件应包含您的my_put_char.h标头;它调用函数。您的其他标题应该(可能)不包括它。 -
请注意,当使用
va_arg时,您必须指定提升类型 —int或unsigned int或double,而不是更短的类型(char、short、float, ETC)。您的行a = va_arg(print, char);正在立即调用未定义的行为。 (标准§7.16.1.1 中的措辞是:…或者如果类型与实际下一个参数的类型不兼容(根据默认参数提升),则行为未定义,除了… i> 并且例外情况不适用于此处(它们与有符号整数和无符号整数以及void *和char *有关)。 -
GCC 编译器支持
__attribute__((format(printf,1,2))符号来检查类似printf()的函数是有原因的——否则很难做到。