Reputation: 5557
Looking at the assembly output by GCC with -O2 I see that if I use printf
GCC will create a function named, for example, _Z6printfPKcz
, which then calls __mingw_vprintf
. What is the purpose for this indirection? Why doesn't printf
translate directly to a call to __mingw_printf
? This is the same for the other related functions, such as sprintf.
Edit:
For the record, I know what name mangling is and how it works. My question is why is the compiler generating the function in the first place, a function which does nothing but forward the arguments to __mingw_vprintf, when it could simply call __mingw_printf directly and save the unnecessary indirection.
In other words, why should this:
printf("%d\n", var);
compile to this:
_Z6printfPKcz:
sub rsp, 56
mov QWORD PTR 72[rsp], rdx
lea rdx, 72[rsp]
mov QWORD PTR 80[rsp], r8
mov QWORD PTR 88[rsp], r9
mov QWORD PTR 40[rsp], rdx
call __mingw_vprintf
add rsp, 56
ret
main:
...
call _Z6printfPKcz
...
when this would suffice
main:
...
call __mingw_printf
...
Upvotes: 4
Views: 1332
Reputation: 58451
There are three things to be realized here and none of the answers contains all three of them (at the moment at least).
_Z6printfPKcz
is the mangled name of printf
. See immibis' answer.
There are several variants of the printf
functions and one or only a few functions implementing the functionality. The latter function(s), whose name start with __
, do the heavy lifting and are internal to the implementation; the functions exposed to the user don't do any significant work, they basically just forward the call either to another forwarding function or to the implementing function. See Mats Petersson's answer.
Inlining of the forwarding function failed in your case. See Basilevs' answer.
I suspect, based on your comments, that your real question is why the inlining failed, why the implementation isn't called directly, without any overhead. Good question, I don't see any valid technical reason for that.
I know that gcc (at least on Linux) has the tendency not to inline functions if link-time optimization is not used, even if both the function body (implementation) and the call site is in the same translation unit (in the same source file).
Try to enable link-time optimization. See -flto
among the Options That Control Optimization. It is very likely that the call will be inlined with link time optimization; that functions seems to be a good candidate for inlining.
UPDATE: I cannot test mingw; here are my tests on Linux. This code:
#include <stdio.h>
int main(int argc, char** argv) {
printf("%d\n", argc);
}
results in the following assembly with optimizations disabled -O0
:
[...]
call printf
[...]
That is, the call to printf
is not inlined. However, already at -O1
I get:
[...]
call __printf_chk
[...]
which means that the call to printf
was inlined and I am directly calling the underlying implementation. It didn't even require link time optimization. You only need to motivate the compiler to do the inlining.
Giving it some thought: The compiler may not inline functions at compile time that are in the C runtime because they are supposed to be accessed at runtime. But it definitely inlines the wrapper function already at -O1
.
As to why a particular version of a compiler on a particular platform fails to inline a particular function, well... If you think it is a performance hit in your application, try to submit a bug report. If I were you, I wouldn't worry to much about it, the IO will cost you a lot more time than that extra function call due to the failed inline.
Upvotes: 1
Reputation: 129364
_pZ6printfPKcz
is a C++ mangled name for a function that has the signature printf(char const*, ...)
- in other words, the actual printf function. Which, it would appear is implemented by calling another function. Since there are half a dozen different variants of printf
(with different types of output, such as output to a file, output to a string, output to console, etc), it makes sense to have a single, "do printf" function - which in this case appears to be __mingq_vprintf
. Since a printf implementation is a few thousand lines of code, we don't really want to duplicate it 6 or so times for all the different variants (I know, because at work I've been implementing a version of printf for OpenCL - it's a pretty complicated function, you DEFINITELY don't want to have the actual code several times over).
You can see the exact definition of printf
in the "stdio.h" here:
http://sourceforge.net/apps/trac/mingw-w64/browser/trunk/mingw-w64-headers/crt/stdio.h?rev=5437#L283
As to exactly why they do this, it's really something you have to ask the developers of mingw - but my assumption would be that they are trying to keep the number of different variants down - for example __mingw_vprintf
is also used to implement the actual vprintf
variant, so that's "half as many variants already".
The extra layering also allows the printf to be switched between narrow (ASCII) and wide characters (so called UNICODE), as can be seen by the macros here:
And you'll hate the mingw developers even more when you realize that __mingw_vprintf turns into just another layer of call:
However, in the whole scheme of a printf implementation, like I said in my comment, it's very small amounts of overhead - the _pformat
code is a good 2000 lines long:
(Which is much smaller than the glibc implementation)
Upvotes: 2
Reputation: 23916
Printf fails to be inlined in this specific case. If inline fails, compiler have to create an explicit function body. Usual behavior without indirection is explained by successful inline.
Upvotes: 1
Reputation: 58868
_Z6printfPKcz
is just the mangled name of printf
- search "name mangling" for more information on that. It's the actual printf function.
__mingw_vprintf
is an internal function which printf
calls - there's no requirement that printf
doesn't call another function to do its work. Maybe __mingw_vprintf
handles all the formatting and printing, and printf
is written like this:
int printf(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
int result = __mingw_vprintf(fmt, va);
va_end(va);
return result;
}
Upvotes: 5