gpt4 book ai didi

c++ - mingw-w64 : slow sprintf in

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:46:05 25 4
gpt4 key购买 nike

<cstdio>吗C++ 中的 header 包含与 <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)进行了计时,发现所有 32 位版本都使用 <cstdio>计时 4.x 秒和 64 位版本 7.x~8.x 秒。所有版本都使用 <stdio.h>定时0.4~0.6秒左右。

更新 2:我反汇编了 gdb 中的主要函数,发现只有一行不同:<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我到达了sprinf里面msvcrt.dll .

_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 wrapper 。正如@Michael Burr 指出的那样,这些包装器的存在是为了与 C99/GNU99 兼容。

您的测试未定义 __USE_MINGW_ANSI_STDIO,因此您不会获得包含 stdio.h 的包装器。但由于它是在构建 libstdc++ 时定义的,您将通过 cstdio 获得它。但是,如果您在包含 stdio.h 之前自己定义它,您将再次获得包装器。

所以你实际上得到了不同的实现,cstdio std::sprintf 不一定与 stdio.h sprintf 相同,至少在涉及到明威。

这是一个测试。首先是来源:

#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>

关于c++ - mingw-w64 : slow sprintf in <cstdio>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17236352/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com