为什么将`const char [N]`和`const char *`传递给view :: c_str()会产生不同的二进制文件,而string_view会产生相同的结果吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么将`const char [N]`和`const char *`传递给view :: c_str()会产生不同的二进制文件,而string_view会产生相同的结果吗?相关的知识,希望对你有一定的参考价值。

使用std::string_viewrange::for_each产生精确组装,const char[N]const char *传递给std::string_view ctor

换句话说,这段代码

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

auto& str = "the quick brown fox is jumping on a lazy dog
the quick brown fox is jumping on a lazy dog
";
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
the quick brown fox is jumping on a lazy dog
"

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

auto& str = "the quick brown fox is jumping on a lazy dog
the quick brown fox is jumping on a lazy dog
";
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
the quick brown fox is jumping on a lazy dog
";
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
the quick brown fox is jumping on a lazy dog
"

哪个组装胜利?

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

view::c_str()可以只用const char*const char [N]产生一个更快的组装吗?

godbolt.org/g/wcQyY1

答案

两个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的代码优化为固定的编译时值,它仍然在编译不同的东西,因此生成的代码不相同并不奇怪。

以上是关于为什么将`const char [N]`和`const char *`传递给view :: c_str()会产生不同的二进制文件,而string_view会产生相同的结果吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何将char赋给const char *

将 Swift 字符串数组转换为 const char * const *

[转载] C++ string, const char*, char* 之间互相转换

C++ 函数形参里的const char作为返回值问题

const char*、const char(&)[N] 和 std::string 的函数重载

const char**与char**之间赋值问题