Why does passing `const char [N]` and `const char *` for viewing :: c_str () give different binaries, and string_view the same?

With std::string_view , range::for_each gives an exact assembly with const char[N] and const char * going to std::string_view ctor

In other words, this code

 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); 

and

 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); 

both outputs are below the assembly:

 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" 

Also, if we pass the string c as const char[N] to 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); 

this gives the exact assembly above, as with one std::string_view .


On the other hand, if we pass the string c as const char* to 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); 

This time it gives another assembly, as shown below:

 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" 

Which build wins?

Why std::string_view decide to provide the same binary?

Can view::c_str() get only one faster build with const char* and const char [N] ?

godbolt.org/g/wcQyY1

+5
source share
1 answer

Both versions of std::string_view call the same constructor, which takes const char* , and then uses std::char_traits::length (basically strlen ) to find the length. The compiler optimizes the value of strlen because the string literal is visible to the compiler, therefore its length is known, but both forms use the same constructor, and both optimize strlen , and therefore both generate the same code.

The version view::c_str uses different overloads depending on whether they are specified by a pointer or an array, see https://github.com/ericniebler/range-v3/blob/1f4a96e9240786801e95a6c70afebf27f04cffeb/include/range/v3/view/c_str .hpp # L68

When specifying a pointer, it should find the length similar to using strlen , but when specifying an array of size N it uses N-1 for the length. Even when the compiler optimizes strlen code as a fixed compilation time value, it still compiles something else, so it’s not at all surprising that the generated code is not identical.

+5
source

Source: https://habr.com/ru/post/1275742/


All Articles