首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >明明威-W64:<cstdio>中的慢冲刺

明明威-W64:<cstdio>中的慢冲刺
EN

Stack Overflow用户
提问于 2013-06-21 13:22:11
回答 1查看 2.4K关注 0票数 6

<cstdio>标头在C++中是否只包含与<stdio.h>相同的函数,但放在std命名空间中?

在用mingw-w64编译的程序中,我遇到了奇怪的效率问题,这比在linux上慢了十多倍。经过一些测试后,我发现问题出在sprintf中。

然后我做了以下测试:

代码语言:javascript
复制
#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倍。以下是时间安排:

代码语言:javascript
复制
$ 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.

UPDATE 1:我进一步使用不同的混合W64构建(rubenvb、drangon和mingw-)计时,发现所有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包含:

代码语言:javascript
复制
0x00000000004077c0 <+0>: jmpq   *0x7c6e(%rip) # 0x40f434 <__imp_sprintf>
0x00000000004077c6 <+6>: nop
0x00000000004077c7 <+7>: nop

__imp_sprintf之后,我到达了msvcrt.dll内部的sprinf

_Z7sprintfPcPKcz包含一些混合代码:

代码语言:javascript
复制
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要使用不同的(慢得多的)函数?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-08-17 00:02:16

libstdc++确实在构建过程中定义了__USE_MINGW_ANSI_STDIO (config/os/mingw32-w64/os_defines.h),这将打开sprintf包装器。正如@Michael所指出的,这些包装器的存在是为了实现C99/GNU99兼容性。

您的测试没有定义__USE_MINGW_ANSI_STDIO,因此您将无法使用stdio.h获得包装器。但是,由于它是在构建libstdc++时定义的,所以您可以使用cstdio获得它。但是,如果您在包含stdio.h之前自己定义它,那么您将再次获得包装器。

因此,您确实得到了不同的实现,而且cstdio std::sprintf不一定与stdio.h sprintf相同,至少在混合方面并非如此。

这是一个测试。首先,来文提交人:

代码语言:javascript
复制
#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);
  }
}

结果:

代码语言:javascript
复制
$ 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>
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17236352

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档