[英]mingw-w64: slow sprintf in <cstdio>
C ++中的<cstdio>
頭是否包含與<stdio.h>
相同的函數但是放在std
命名空間中?
我在使用mingw-w64編譯的程序中遇到了奇怪的效率問題,這比在linux上慢十倍。 經過一些測試后,我發現問題出現在sprintf
。
然后我做了以下測試:
#include <stdio.h>
// #include <cstdio>
// using std::sprintf;
int main () {
int i;
for (i = 0; i < 500000; i++){
char x[100];
sprintf(x, "x%dx%dx", i, i<<2);
}
}
使用<stdio.h>
編譯時,它比使用<cstdio>
快15倍。 這是時間:
$ time ./stdio
real 0m0.557s
user 0m0.046s
sys 0m0.046s
$ time ./cstdio
real 0m7.465s
user 0m0.031s
sys 0m0.077s
$ g++ --version
g++.exe (rubenvb-4.8-stdthread) 4.8.1 20130324 (prerelease)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
更新1 :我進一步定時使用不同的mingw-w64版本(rubenvb,drangon和mingw-build),並發現使用<cstdio>
所有32位版本定時4.x秒和64位版本7.x~8.x秒。 所有使用<stdio.h>
版本的時間約為0.4~0.6秒。
更新2 :我在gdb中反匯編了main函數,發現只有一行不同: <stdio.h>
版本調用callq 0x4077c0 <sprintf>
但<cstdio>
版本調用callq 0x407990 <_Z7sprintfPcPKcz>
。
sprintf
包含:
0x00000000004077c0 <+0>: jmpq *0x7c6e(%rip) # 0x40f434 <__imp_sprintf>
0x00000000004077c6 <+6>: nop
0x00000000004077c7 <+7>: nop
在__imp_sprintf
之后,我到達了msvcrt.dll
的sprinf
。
_Z7sprintfPcPKcz
包含一些mingw代碼:
0x0000000000407990 <+0>: push %rbp
0x0000000000407991 <+1>: push %rbx
0x0000000000407992 <+2>: sub $0x38,%rsp
0x0000000000407996 <+6>: lea 0x80(%rsp),%rbp
0x000000000040799e <+14>: mov %rcx,-0x30(%rbp)
0x00000000004079a2 <+18>: mov %r8,-0x20(%rbp)
0x00000000004079a6 <+22>: mov %r9,-0x18(%rbp)
0x00000000004079aa <+26>: mov %rdx,-0x28(%rbp)
0x00000000004079ae <+30>: lea -0x20(%rbp),%rax
0x00000000004079b2 <+34>: mov %rax,-0x58(%rbp)
0x00000000004079b6 <+38>: mov -0x58(%rbp),%rdx
0x00000000004079ba <+42>: mov -0x28(%rbp),%rax
0x00000000004079be <+46>: mov %rdx,%r8
0x00000000004079c1 <+49>: mov %rax,%rdx
0x00000000004079c4 <+52>: mov -0x30(%rbp),%rcx
0x00000000004079c8 <+56>: callq 0x402c40 <__mingw_vsprintf>
0x00000000004079cd <+61>: mov %eax,%ebx
0x00000000004079cf <+63>: mov %ebx,%eax
0x00000000004079d1 <+65>: add $0x38,%rsp
0x00000000004079d5 <+69>: pop %rbx
0x00000000004079d6 <+70>: pop %rbp
為什么cstdio
使用不同(而且速度慢得多)的函數?
libstdc ++在構建期間定義了__USE_MINGW_ANSI_STDIO
( config/os/mingw32-w64/os_defines.h
),這將打開mingw sprintf
包裝器。 正如@Michael Burr指出的那樣,這些包裝器存在C99 / GNU99兼容性。
您的測試沒有定義__USE_MINGW_ANSI_STDIO
,因此您將無法獲得stdio.h
的包裝器。 但是因為它是在構建libstdc ++時定義的,所以你可以使用cstdio
獲取它。 如果你在包含stdio.h
之前自己定義它,你將再次得到包裝器。
所以你確實得到了不同的實現,而cstdio std::sprintf
不一定與stdio.h sprintf
相同,至少在涉及到mingw時不一樣。
這是一個測試。 首先來源:
#ifdef USE_STDIO
#include <stdio.h>
#else
#include <cstdio>
using std::sprintf;
#endif
int main () {
int i;
for (i = 0; i < 500000; i++){
char x[100];
sprintf(x, "x%dx%dx", i, i<<2);
}
}
結果:
$ g++ -o test_cstdio.exe test.cc
$ g++ -o test_stdio.exe -DUSE_STDIO test.cc
$ g++ -o test_stdio_wrap.exe -DUSE_STDIO -D__USE_MINGW_ANSI_STDIO test.cc
$ for x in test_*.exe; do ( echo $x; objdump -d $x | grep sprintf; echo ); done
test_cstdio.exe
40154a: e8 41 64 00 00 callq 407990 <_Z7sprintfPcPKcz>
0000000000402c40 <__mingw_vsprintf>:
0000000000407990 <_Z7sprintfPcPKcz>:
4079c8: e8 73 b2 ff ff callq 402c40 <__mingw_vsprintf>
test_stdio.exe
40154a: e8 71 62 00 00 callq 4077c0 <sprintf>
00000000004077c0 <sprintf>:
4077c0: ff 25 6e 6c 00 00 jmpq *0x6c6e(%rip) # 40e434 <__imp_sprintf>
test_stdio_wrap.exe
40154a: e8 41 64 00 00 callq 407990 <_Z7sprintfPcPKcz>
0000000000402c40 <__mingw_vsprintf>:
0000000000407990 <_Z7sprintfPcPKcz>:
4079c8: e8 73 b2 ff ff callq 402c40 <__mingw_vsprintf>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.