特定的 C 函数如何工作?
我正在尝试学习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 如何执行上述任务吗?
I am trying to learn C and am very confused already.
In the OOP languages i have used there exists the ability to perform method overloading, where the same function could have different parameter types and call whichever was the most appropriate.
Now in C i know that this is not the case so i cant figure out the following problem, How printf() works.
For example:
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);
Now as C does'nt support function overloading, How does printf manage to take any number of arguments, of any type, and then work correctly with them?
I have tried to find the printf() working by downloading the glibc source package but can quite seem to find it, though i'll keep looking.
Could anyone here explain how C performs the above task?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
C 支持一种称为“varargs”的函数签名类型,意思是“可变(数量)参数”。这样的函数必须至少有一个必需的参数。对于
printf
,格式字符串是必需的参数。通常,在基于堆栈的计算机上,当您调用任何 C 函数时,参数会从右到左压入堆栈。这样,函数的第一个参数就位于堆栈的“顶部”,就在返回地址之后。
定义了 C 宏,允许您检索变量参数。
关键点是:
printf()
,如果格式字符串错误,代码将从内存中读取无效结果,可能会崩溃。va_start
初始化,用va_arg
递增,并用va_end
释放。我已经发布了大量您可能会对相关问题感兴趣的代码:
存储 va_list 以便以后在 C/C++ 中使用的最佳方式
这是一个
printf()
仅格式化整数(“%d”):C supports a type of function signature called "varargs" meaning "variable (number of) arguments". Such a function must have at least one required argument. In the case of
printf
, the format string is a required argument.Generally, on a stack-based machine, when you call any C function, the arguments are pushed onto the stack from right-to-left. In this way, the first argument to the function is that found on the "top" of the stack, just after the return address.
There are C macros defined which allow you to retrieve the variable arguments.
The key points are:
printf()
, if the format string is wrong, the code will read invalid results from memory, possibly crashing.va_start
, incremented withva_arg
, and released withva_end
.I have posted a ton of code you may find interesting on the related question:
Best Way to Store a va_list for Later Use in C/C++
Here's a skeleton of a
printf()
which only formats integers ("%d"):在内部,
printf
将(至少通常)使用 stdarg.h 中的一些宏。总体思路是(大大扩展的版本),如下所示:充实它确实涉及相当多的工作——处理字段宽度、精度、更多转换等。然而,这足以至少给出一个如何在函数内检索不同类型的不同参数的风格。
Internally,
printf
will (at least usually) use some macros from stdarg.h. The general idea is (a greatly expanded version of) something like this:Fleshing it out does involve quite a bit of work -- dealing with field width, precision, more conversions, etc. This is enough, however, to at least give a flavor of how you retrieve varying arguments of varying types inside your function.
(不要忘记,如果您使用 gcc(和 g++?),您可以在编译器选项中传递
-Wformat
来让编译器检查参数的类型是否与格式匹配我希望其他编译器也有类似的选项。)迷信。它假设您已确保参数的类型与格式字符串中的相应字母完全匹配。当调用 printf 时,所有参数都以二进制表示,毫不客气地连接在一起,并作为单个大参数有效地传递给 printf。如果它们不匹配,你就会遇到问题。当
printf
遍历格式字符串时,每次看到%d
时,它都会从参数中获取 4 个字节(假设是 32 位,则 64 位则为 8 个字节)当然是位整数)并且它将把它们解释为整数。现在也许您实际上传递了一个
double
(通常占用的内存是int
的两倍),在这种情况下printf
将只占用 32这些位并将它们表示为整数。然后下一个格式字段(可能是%d
)将占用双精度的其余部分。所以基本上,如果类型不完全匹配,您将得到严重乱码的数据。如果你不幸的话,你将会有未定义的行为。
(Don't forget that, if you're using gcc (and g++?), you can pass
-Wformat
in the compiler options to get the compiler to check that the types of the arguments match the formatting. I hope other compilers have similar options.)Blind faith. It assumes that you have ensured that the types of the arguments match perfectly with the corresponding letters in your format string. When
printf
is called, all the arguments are represented in binary, unceremoniously concatenated together, and passed effectively as a single big argument toprintf
. If they don't match, you'll have problems. Asprintf
iterates through the format string, every time it see%d
it will take 4 bytes from the arguments (assuming 32-bit, it would be 8 bytes for 64-bit ints of course) and it will interpret them as an integer.Now maybe you actually passed a
double
(typically taking up twice as much memory as anint
), in which caseprintf
will just take 32 of those bits and represented them as an integer. Then the next format field (maybe a%d
) will take the rest of the double.So basically, if the types don't match perfectly you'll get badly garbled data. And if you're unlucky you will have undefined behaviour.