实际上,我正在尝试使用可变参数在C语言中编写自己的printf()
函数。但是我无法获得正确的解决方案。有人能帮我吗?
在实现printf()函数之前,我们必须处理一个不寻常的问题,即可变参数。由于我们知道printf除了字符串以外还可以接受许多参数,因此我们需要使用一个标准库stdargs.h来处理这个可变参数问题。在这个实现上下文中,我们不需要学习整个stdarg.h库,因为我们只需要直接理解C程序中这些库的一些宏函数。
#include<stdio.h>
#include<stdarg.h>
void Myprintf(char *,...); //Our printf function
char* convert(unsigned int, int); //Convert integer number into octal, hex, etc.
int main()
{
Myprintf(" WWW.FIRMCODES.COM \n %d", 9);
return 0;
}
void Myprintf(char* format,...)
{
char *traverse;
unsigned int i;
char *s;
//Module 1: Initializing Myprintf's arguments
va_list arg;
va_start(arg, format);
for(traverse = format; *traverse != '\0'; traverse++)
{
while( *traverse != '%' )
{
putchar(*traverse);
traverse++;
}
traverse++;
//Module 2: Fetching and executing arguments
switch(*traverse)
{
case 'c' : i = va_arg(arg,int); //Fetch char argument
putchar(i);
break;
case 'd' : i = va_arg(arg,int); //Fetch Decimal/Integer argument
if(i<0)
{
i = -i;
putchar('-');
}
puts(convert(i,10));
break;
case 'o': i = va_arg(arg,unsigned int); //Fetch Octal representation
puts(convert(i,8));
break;
case 's': s = va_arg(arg,char *); //Fetch string
puts(s);
break;
case 'x': i = va_arg(arg,unsigned int); //Fetch Hexadecimal representation
puts(convert(i,16));
break;
}
}
//Module 3: Closing argument list to necessary clean-up
va_end(arg);
}
char *convert(unsigned int num, int base)
{
static char Representation[]= "0123456789ABCDEF";
static char buffer[50];
char *ptr;
ptr = &buffer[49];
*ptr = '\0';
do
{
*--ptr = Representation[num%base];
num /= base;
}while(num != 0);
return(ptr);
}
while( *traverse != '%' ){
后面添加 if( *traverse == '\0') return;
。 - GabrielTLinux va_start(3) man page提供了非常好的编写此类函数的示例(更简单,但通常所有主要部分都在其中)。此外,您可以检查几乎任何libstdc实现。
这个答案 可以帮助你理解如何编写可变参数函数。请注意,没有进行错误/边界检查,也没有设置属性告诉编译器哪些参数可能是合适的,与仅使用printf()相比没有任何优势。
它可能是你正在寻找的示例,也可能不是。
相关代码片段(稍微扩展一下):
#include <stdarg.h>
void _printf(FILE *out, va_list ap)
{
vfprintf(out, fmt, ap);
}
void printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
_printf(stdout, ap);
va_end(ap);
}
至少有两本书提供了关于如何编写像printf()
一样的格式化函数的良好解释(并且包含完整的工作示例):
<stdio.h>
所需的所有函数。 - Jonathan Leffler它只适用于“%s”格式说明符。但我认为这仍然很有用。
void printf(char* str, ...)
{
char* s;
va_list vl;
va_start(vl, str);
for (char* ptr = str; *ptr != '\0'; ptr++)
{
if (*ptr == '%')
{
ptr++;
s = va_arg(vl, char*);
while (*s != '\0')
putchar(*s++);
}
putchar(*ptr);
}
va_end(vl);
}
int main()
{
char str[60] = "String Array is initialized";
printf("abcd %s abcd \n", str);
printf("It work!\n");
}
#include <stdarg.h>
int my_printf(const char *format, ...)
{
va_list args;
va_start(args, format);
int i = 0;
while (format[i])
{
if (format[i] == '%')
{
i++;
switch (format[i])
{
case 'd':
{
int x = va_arg(args, int);
printf("%d", x);
break;
}
case 'f':
{
double x = va_arg(args, double);
printf("%f", x);
break;
}
case 'c':
{
int x = va_arg(args, int);
printf("%c", x);
break;
}
case 's':
{
char *x = va_arg(args, char*);
printf("%s", x);
break;
}
case 'x':
case 'X':
{
int x = va_arg(args, int);
printf("%x", x);
break;
}
case 'p':
{
void *x = va_arg(args, void*);
printf("%p", x);
break;
}
case '%':
putchar('%');
break;
default:
putchar(format[i]);
break;
}
}
else
{
putchar(format[i]);
}
i++;
}
va_end(args);
return 0;
}
int main()
{
int x = 5;
double y = 3.14;
char c = 'a';
char *str = "Hello World!";
my_printf("The value of x is %d, y is %f, c is %c, str is %s", x, y, c, str);
return 0;
}
我认为创建一个新的函数,而不使用printf()函数来完成printf()函数的所有功能是相当困难的。因此,我尝试了这种方式。 在这里,我为代码添加了文档- Printf()函数
printf
实现 my_printf
是一种有趣的方法... 去除 printf
的任务留给用户作为练习。 - chqrlieprintf
的引用通常很容易,但完全支持标志、宽度和精度字段是繁琐而棘手的,而完全支持浮点转换确实非常困难。为所有值和参数生成预期输出是C库中最困难的任务之一。 - chqrlie#include <stdio.h>
#include <stdarg.h>
#include <string.h>
// You can write your own low level function to write to display or hardware
void local_put(char c){
putchar(c);
}
void decimal_to_baseN(char *converted, unsigned int num, int base)
{
if (num == 0) {
converted[0] = '0';
converted[1] = '\0';
return;
}
int MAX_REP_LEN = 250;
char NUM_BASE[] = "0123456789ABCDEF";
char buffer[MAX_REP_LEN];
int i = MAX_REP_LEN - 1;
while (num != 0) {
buffer[i--] = NUM_BASE[num % base];
num /= base;
}
int counter = 0;
for (int j = i + 1; j <= MAX_REP_LEN - 1; j++) {
converted[counter++] = buffer[j];
}
converted[counter] = '\0';
}
void my_print(char *c, ...)
{
int num;
va_list arg;
va_start(arg, c);
char outbuf[2048];
int i;
char *ch;
double db_val;
unsigned int uint_val;
while(*c!='\0'){
if(*c=='%'){
c++; // To incement to the formating character
// processing the formatting character
switch(*c){
case 'b':
case 'B':
case 'h':
case 'H':
case 'O':
case 'o':
case 'd':
case 'D':
case 'i':
case 'I':
num = va_arg(arg, int);
if(num<0){
// Simple - sign is used instead of 2s complement
local_put('-');
num = num * -1;
}
if(*c=='b' || *c=='B'){
decimal_to_baseN(outbuf, num, 2);
}else if(*c=='o' || *c=='O'){
decimal_to_baseN(outbuf, num, 8);
}else if(*c=='d' || *c=='D'){
decimal_to_baseN(outbuf, num, 10);
}else if(*c=='h' || *c=='H'){
decimal_to_baseN(outbuf, num, 16);
}
for(int i=0;outbuf[i]!='\0';i++){
local_put(outbuf[i]);
}
break;
case 'c':
case 'C':
num = va_arg(arg, int);
local_put(num);
break;
case 's':
case 'S':
ch = va_arg(arg, char*);
while(*ch!='\0'){
local_put(*ch++);
}
break;
case 'f':
case 'F':
db_val = va_arg(arg, double);
sprintf(outbuf, "%f", db_val);
for(int i=0;outbuf[i]!='\0';i++){
local_put(outbuf[i]);
}
break;
case 'u':
case 'U':
uint_val = va_arg(arg, unsigned int);
sprintf(outbuf, "%u", uint_val);
for(int i=0;outbuf[i]!='\0';i++){
local_put(outbuf[i]);
}
break;
}
}else{
local_put(*c);
}
c++;
}
va_end(arg);
}
int main()
{
int num = 100;
my_print("The Decimal: %d\r\n", num);
my_print("The Unsigned int: %u\r\n", 4294967295);
my_print("The Binary: %b\r\n", num);
my_print("The Octel: %o\r\n", num);
my_print("The Hex: %h\r\n", 999);
my_print("The Character: %c\r\n", 'C');
my_print("The String: %s\r\n", "Annie");
my_print("The Float: %f\r\n", 4.35);
return 0;
}
stdarg.h
吗?你是不知道如何使用它,还是在解析格式字符串时遇到了麻烦? - dmckee --- ex-moderator kitten