我正在努力学习C并且我已经非常困惑了。
在我使用的OOP语言中,存在执行方法重载的能力,其中相同的函数可以具有不同的参数类型并且调用哪个是最合适的。
现在在C中我知道情况并非如此,所以我无法弄清楚以下问题,printf()如何工作。
例如:
char chVar = 'A'; int intVar = 123; float flVar = 99.999; printf("%c - %i - %f n",chVar, intVar, flVar); printf("%i - %f - %c n",intVar, flVar, chVar); printf("%f - %c - %i n",flVar, chVar, intVar);
现在因为C不支持函数重载,printf如何设法获取任何类型的任意数量的参数,然后正确地使用它们?
我试图通过下载glibc源程序包找到printf()工作,但似乎很容易找到它,虽然我会继续寻找。
这里的任何人都可以解释C如何执行上述任务吗?
C支持一种称为“varargs”的函数签名,意思是“变量(数量)参数”。 这样的函数必须至少有一个必需的参数。 对于printf
,格式字符串是必需参数。
通常,在基于堆栈的机器上,当您调用任何C函数时,参数将从右向左推入堆栈。 这样,函数的第一个参数是在堆栈的“顶部”找到的,就在返回地址之后。
定义了C宏,允许您检索变量参数。
关键点是:
我发布了大量您可能会对相关问题感兴趣的代码:
存储va_list以便以后在C / C ++中使用的最佳方法
这是printf()
的骨架,它只格式化整数(“%d”):
int printf( const char * fmt, ... ) { int d; /* Used to store any int arguments. */ va_list args; /* Used as a pointer to the next variable argument. */ va_start( args, fmt ); /* Initialize the pointer to arguments. */ while (*fmt) { if ('%' == *fmt) { fmt ++; switch (*fmt) { case 'd': /* Format string says 'd'. */ /* ASSUME there is an integer at the args pointer. */ d = va_arg( args, int); /* Print the integer stored in d... */ break; } } else /* Not a format character, copy it to output. */ fmt++; } va_end( args ); }
在内部, printf
将(至少通常)使用stdarg.h中的一些宏。 一般的想法是(一个大大扩展的版本)这样的事情:
#include #include #include int my_vfprintf(FILE *file, char const *fmt, va_list arg) { int int_temp; char char_temp; char *string_temp; char ch; int length = 0; char buffer[512]; while ( ch = *fmt++) { if ( '%' == ch ) { switch (ch = *fmt++) { /* %% - print out a single % */ case '%': fputc('%', file); length++; break; /* %c: print out a character */ case 'c': char_temp = va_arg(arg, int); fputc(char_temp, file); length++; break; /* %s: print out a string */ case 's': string_temp = va_arg(arg, char *); fputs(string_temp, file); length += strlen(string_temp); break; /* %d: print out an int */ case 'd': int_temp = va_arg(arg, int); itoa(int_temp, buffer, 10); fputs(buffer, file); length += strlen(buffer); break; /* %x: print out an int in hex */ case 'x': int_temp = va_arg(arg, int); itoa(int_temp, buffer, 16); fputs(buffer, file); length += strlen(buffer); break; } } else { putc(ch, file); length++; } } return length; } int my_printf(char const *fmt, ...) { va_list arg; int length; va_start(arg, fmt); length = my_vfprintf(stdout, fmt, arg); va_end(arg); return length; } int my_fprintf(FILE *file, char const *fmt, ...) { va_list arg; int length; va_start(arg, fmt); length = my_vfprintf(file, fmt, arg); va_end(arg); return length; } #ifdef TEST int main() { my_printf("%s", "Some string"); return 0; } #endif
充实它确实涉及相当多的工作 – 处理字段宽度,精度,更多转换等。然而,这足以说明如何在函数内检索不同类型的不同参数。
(不要忘记,如果你正在使用gcc(和g ++?),你可以在编译器选项中传递-Wformat
,让编译器检查参数的类型是否与格式匹配。我希望其他编译器有类似的选项)。
这里的任何人都可以解释C如何执行上述任务吗?
迷信。 它假定您已确保参数类型与格式字符串中的相应字母完全匹配。 当调用printf
,所有参数都以二进制表示,毫不客气地连接在一起,并作为printf
的一个大参数有效地传递。 如果它们不匹配,你就会遇到问题。 当printf
遍历格式字符串时,每次看到%d
,它将从参数中获取4个字节(假设32位,当然,对于64位整数,它将是8个字节)并且它将它们解释为整数。
现在也许你实际上传递了一个double
(通常占用的内存是int
两倍),在这种情况下, printf
将只取32个这些位并将它们表示为整数。 然后下一个格式字段(可能是%d
)将取其余的双倍。
所以基本上,如果类型不完全匹配,你会得到严重乱码的数据。 如果你运气不好,你会有不确定的行为。
需要了解更多c/c++开发分享特定的Cfunction如何工作?,也可以关注C/ C++技术分享栏目—计算机技术网(www.ctvol.com)!
以上就是c/c++开发分享特定的Cfunction如何工作?相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/980153.html