程序:
#ifndef PRINTF_H
#define PRINTF_H
#include "my_put_char.h"
int my_printf(char *str, ...);
#endif
这是我的函数的Header文件。
#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
进行测试以显示一个字符。
当我my_print("%c", 'd');
main.c
时
它编译并显示d
。
但是当我my_print("%c", "hi");
时,它仍会编译并显示一个数字。
问题:
写a = va_arg(print, char);
之后(或之前)有没有办法检查我的输入是否是不同的数据类型?
如果我的输入是不同的数据类型,我正在尝试显示错误。
我在这个问题上已经有2天了,找不到任何答案。 非常感谢你的时间!
答案 0 :(得分:3)
当我
my_print("%c", "hi");
时,它仍会编译并显示一个数字
您已获得一些undefined behavior,因此请scared。您的my_printf
会使用错误类型的参数调用va_arg
(预期char
提升为int
,获得char*
。
为了解释发生了什么,你应该深入了解实现细节(查看汇编代码,例如gcc -Wall -fverbose-asm -O -S
;研究你的processor,instruction set architecture,application binary interface和calling conventions)。 您不想这样做,可能需要数年时间才能重现。
立即阅读Lattner's blog on UB!
您还可以使用gcc
使用function attributes。不要忘记编译所有警告和调试信息(gcc -Wall -Wextra -g
)
编写a = va_arg(print, char);
之后有没有办法检查我的输入是否是不同的数据类型?
不,不是真的,也不是永远。但format
函数属性可能会有所帮助。您还可以花费数月时间使用自己的plugin或一些GCC MELT扩展程序自定义GCC(这不值得您花时间)。请注意Halting Problem和Rice's Theorem(每个static源代码program analysis都具有挑战性)。另请参阅Frama-C等源分析工具。
我正在实施printf功能
BTW研究free software的现有C standard library实施的源代码(例如GNU glibc和musl-libc)可能是鼓舞人心的;它们基于syscalls(2)。