首页 > 解决方案 > 与编译时未解析的字符串文字进行比较

问题描述

我最近发现了类似于以下几行的内容:

#include <string>

// test if the extension is either .bar or .foo
bool test_extension(const std::string& ext) {
    return ext == ".bar" || ".foo";
    // it obviously should be
    // return ext == ".bar" || ext == ".foo";
}

该功能显然没有按照评论的建议进行。但这不是重点。请注意,这不是Can you use 2 or more OR conditions in an if 语句的副本?因为我完全知道您将如何正确编写函数!


我开始想知道编译器如何处理这个片段。我的第一个直觉是这将被编译为return true;基本上。将该示例插入Godbolt,表明 GCC 9.2 和 clang 9 都没有通过优化进行此优化-O2

但是,将代码更改为1

#include <string>

using namespace std::string_literals;

bool test_extension(const std::string& ext) {
    return ext == ".bar"s || ".foo";
}

似乎可以解决问题,因为程序集现在本质上是:

mov     eax, 1
ret

所以我的核心问题是:有什么我错过的东西不允许编译器对第一个片段进行相同的优化吗?


1这样甚至不会编译,因为".foo"s编译器不想将 a 转换std::stringbool;-)


编辑

以下代码也得到“适当”优化return true;

#include <string>

bool test_extension(const std::string& ext) {
    return ".foo" || ext == ".bar";
}

标签: c++stringc++14compiler-optimization

解决方案


这会让你更加困惑:如果我们创建一个自定义 char 类型MyCharT并使用它来制作我们自己的自定义会发生std::basic_string什么?

#include <string>

struct MyCharT {
    char c;
    bool operator==(const MyCharT& rhs) const {
        return c == rhs.c;
    }
    bool operator<(const MyCharT& rhs) const {
        return c < rhs.c;
    }
};
typedef std::basic_string<MyCharT> my_string;

bool test_extension_custom(const my_string& ext) {
    const MyCharT c[] = {'.','b','a','r', '\0'};
    return ext == c || ".foo";
}

// Here's a similar implementation using regular
// std::string, for comparison
bool test_extension(const std::string& ext) {
    const char c[] = ".bar";
    return ext == c || ".foo";
}

当然,自定义类型不能比普通类型更容易优化char,对吧?

这是生成的程序集:

test_extension_custom(std::__cxx11::basic_string<MyCharT, std::char_traits<MyCharT>, std::allocator<MyCharT> > const&):
        mov     eax, 1
        ret
test_extension(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
        sub     rsp, 24
        lea     rsi, [rsp+11]
        mov     DWORD PTR [rsp+11], 1918984750
        mov     BYTE PTR [rsp+15], 0
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::compare(char const*) const
        mov     eax, 1
        add     rsp, 24
        ret

现场观看!


脑洞大开!

那么,我的“自定义”字符串类型和 之间有什么区别std::string

小字符串优化

至少在 GCC 上,Small String Optimization实际上被编译成 libstdc++ 的二进制文件。这意味着,在编译您的函数期间,编译器无法访问此实现,因此它无法知道是否有任何副作用。因此,它无法优化对compare(char const*)away 的调用。我们的“自定义”类没有这个问题,因为 SSO 仅针对 plain 实现std::string

顺便说一句,如果你用 编译-std=c++2a编译器会优化它。不幸的是,我对 C++ 20 还不够精明,还不知道是什么变化使这成为可能。


推荐阅读