【问题标题】:Why does passing `const char[N]` and `const char*` to view::c_str() yield different binaries, while string_view produces the same?为什么将 `const char[N]` 和 `const char*` 传递给 view::c_str() 会产生不同的二进制文件,而 string_view 会产生相同的二进制文件?
【发布时间】:2018-03-06 15:51:07
【问题描述】:

使用std::string_viewrange::for_each 产生 exact 程序集,const char[N]const char * 都传递给 std::string_view ctor

也就是说,这段代码

auto str = "the quick brown fox is jumping on a lazy dog\nthe quick brown fox is jumping on a lazy dog\n";
ranges::for_each(std::string_view{str}, std::putchar);

auto& str = "the quick brown fox is jumping on a lazy dog\nthe quick brown fox is jumping on a lazy dog\n";
ranges::for_each(std::string_view{str}, std::putchar);

两者都屈服于装配:

main:                                   # @main
        pushq   %rbx
        movq    $-90, %rbx
.LBB0_1:                                # =>This Inner Loop Header: Depth=1
        movsbl  .L.str+90(%rbx), %edi
        movq    stdout(%rip), %rsi
        callq   _IO_putc
        addq    $1, %rbx
        jne     .LBB0_1
        xorl    %eax, %eax
        popq    %rbx
        retq
.L.str:
        .asciz  "the quick brown fox is jumping on a lazy dog\nthe quick brown fox is jumping on a lazy dog\n"

此外,如果我们将 c 字符串作为const char[N] 传递给ranges::view::c_str()

auto& str = "the quick brown fox is jumping on a lazy dog\nthe quick brown fox is jumping on a lazy dog\n";
ranges::for_each(ranges::view::c_str(str), std::putchar);

这会产生上面的精确装配,就像 std::string_view 产生的一样。


另一方面,如果我们将 c 字符串作为const char* 传递给ranges::view::c_str()

auto str = "the quick brown fox is jumping on a lazy dog\nthe quick brown fox is jumping on a lazy dog\n";
ranges::for_each(ranges::view::c_str(str), std::putchar);

这一次它产生了一个不同的程序集,如下所示:

main:                                   # @main
        pushq   %rbx
        movb    $116, %al
        movq    $-90, %rbx
.LBB0_1:                                # =>This Inner Loop Header: Depth=1
        movsbl  %al, %edi
        movq    stdout(%rip), %rsi
        callq   _IO_putc
        movzbl  .L.str+91(%rbx), %eax
        incq    %rbx
        jne     .LBB0_1
        xorl    %eax, %eax
        popq    %rbx
        retq
.L.str:
        .asciz  "the quick brown fox is jumping on a lazy dog\nthe quick brown fox is jumping on a lazy dog\n"

哪个大会获胜?

为什么std::string_view 决定生成相同的二进制文件?

view::c_str() 能否同时使用const char*const char [N] 产生一个更快的组装?

godbolt.org/g/wcQyY1

【问题讨论】:

  • 我建议你挤进c++标签。它比特定于版本的 c++ 标签更受欢迎。

标签: c++ optimization range-v3 string-view


【解决方案1】:

两个std::string_view 版本调用相同的构造函数,它采用const char*,然后使用std::char_traits::length(基本上是strlen)来查找长度。编译器优化了strlen,因为字符串文字对编译器是可见的,所以它的长度是已知的,但是两种形式都使用完全相同的构造函数,并且都优化了strlen,因此都生成了相同的代码。

view::c_str 版本使用不同的重载,具体取决于给定的是指针还是数组,请参阅 https://github.com/ericniebler/range-v3/blob/1f4a96e9240786801e95a6c70afebf27f04cffeb/include/range/v3/view/c_str.hpp#L68

当给定一个指针时,它必须找到类似于使用strlen 的长度,但是当给定一个大小为N 的数组时,它使用N-1 作为长度。即使编译器将类似strlen 的代码优化为固定的编译时间值,它仍然在编译不同的东西,因此生成的代码不相同也就不足为奇了。

【讨论】:

  • 这很有趣。似乎编译器非常擅长优化strlen。我刚刚发现ranges::span<const char>(str,strlen(str)) 也恰好产生了第一个版本。 godbolt.org/g/HSebUR
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-06
  • 2016-04-19
  • 1970-01-01
  • 1970-01-01
  • 2013-11-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多