[英]Working of printf() function in C (Only Variable number of Arguments)
我問這個問題是為了理解printf作為一個接受可變長度參數的函數的工作原理。
我正在從這里學習可變數量的參數概念,讓我感到困惑的是傳入va_arg(va_list,datatype)的數據類型。 我的意思是他們在這里提到了一種數據類型。 我們需要傳遞具有不同數據類型的參數的情況呢? 在printf函數中也是如此。
printf 如何准確計算出不同類型的參數類型。 根據我的想法,他們必須檢查第一個 const char* 參數中的每個 % 符號,然后檢查特定數據類型的標記。
以下變量參數列表函數向您解釋了printf
將如何工作。
#include <stdio.h>
#include <stdarg.h>
void foo(char *fmt, ...) // This Function works like same as printf
{
va_list ap;
int d;
char c, *s;
va_start(ap, fmt);
while (*fmt)
switch (*fmt++) {
case 's': /* string */
s = va_arg(ap, char *);
printf("string %s\n", s);
break;
case 'd': /* int */
d = va_arg(ap, int);
printf("int %d\n", d);
break;
case 'c': /* char */
/* need a cast here since va_arg only
takes fully promoted types */
c = (char) va_arg(ap, int);
printf("char %c\n", c);
break;
}
va_end(ap);
}
main()
{
// call the foo function here
// like foo("%d%s%c",3,"hai",'a');
}
有關更多參考,請參閱va_arg的手冊頁
它不支持char
和float
值,因此我們需要對其進行類型轉換。 對於float
,您需要對double
精度值進行類型轉換。
printf
是一個函數,而不是宏。 它被定義為
int printf(const char *, ...)
並且有可變數量的參數。
printf
使用字符串來定義傳遞的參數數量。 每個 % 用於向堆棧移動並檢索參數。
所以,如果你通過
"%d %d %d", 1, 2
然后將顯示 1、2 和任意值。 這很糟糕:你可以使用這個函數沿着堆棧向下走。
通過時
"%d %d", 1, 2, 3
然后將顯示 1 和 2。 並且行為未定義:通常使用 __cdecl 調用約定,因此堆棧不會因為被調用者清理而損壞。
是的,它會檢查 %X 以查看要使用的數據類型或標志。 沒有這個,它就無法知道。 唯一的方法是使用 C++ 的可變參數模板。 除此之外,C如下所示..
此示例使用fwrite
將數據寫入stdout
。
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cstdarg>
void C_Printf(const char *fmt, ...)
{
int fmtLength = strlen(fmt);
va_list VariableArgs;
va_start(VariableArgs, fmt);
for (int I = 0; I < fmtLength; I++)
{
if (fmt[I] == '%')
{
switch(tolower(fmt[++I]))
{
case 'f':
{
double d = va_arg(VariableArgs, double);
fwrite(&d, sizeof(double), 1, stdout);
}
break;
case 'i':
case 'd':
{
int i = va_arg(VariableArgs, int);
fwrite(&i, sizeof(int), 1, stdout);
}
break;
case 's':
{
const char *str = va_arg(VariableArgs, const char *);
fwrite(&str[0], sizeof(char), strlen(str), stdout);
}
break;
default:
break;
}
}
else
fwrite(&fmt[I], sizeof(char), 1, stdout);
}
va_end(VariableArgs);
}
int main()
{
C_Printf("%s", "hello there");
}
在一些自由軟件標准 C 庫實現中查看printf
的源代碼,例如GNU libc或musl-libc 。 我發現musl-libc
非常易讀,查看src/stdio/printf.c然后查看src/stdio/vfprintf.c (真正的工作完成的地方)。 當然它根據格式控制字符串使用va_arg
(參見stdarg(3) 。注意va_arg
是在編譯器內部實現的,通過GCC中的__builtin_va_arg
)。 GCC 還內置了對printf
的支持
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.