【问题标题】:const char * constexpr evaluated at compile time and at run timeconst char * constexpr 在编译时和运行时评估
【发布时间】:2017-05-26 11:18:51
【问题描述】:

在下面的示例中,我使用static_assert 来验证foo 是在编译时确定的。 static_assert 通过了,我检查了它实际上处于活动状态的不正确条件。这意味着foo 在编译时是已知的。但如果我使用调试器单步执行代码,我会看到 skip_first_word 也在运行时执行。

// Skip the first word in p_str
constexpr const char * skip_first_word(const char * p_str) {
    return (*p_str == '\0') ? p_str : 
        (*p_str == ' ') ? p_str + 1 : 
        skip_first_word(p_str + 1);
}

// constexpr to calculate the length of a string
constexpr size_t str_len(const char * p_str) {
    return (*p_str == '\0') ? 0 : str_len(p_str + 1) + 1;
}

int main()
{
    constexpr auto foo = skip_first_word("Hello, World!");
    constexpr auto foo_size = str_len(foo);
    static_assert(foo_size == 6, "Wrong size");

    // This assert successfully fails
    // static_assert(foo_size == 7, "Wrong size");

    // Prevent optimizations
    for(auto ptr = foo; *ptr != '\0'; ++ptr) {
        volatile auto sink = ptr;
    }
    volatile auto sink = &foo_size;

    return 0;
}

这里发生了什么?为什么编译时计算的foo不能在运行时使用?

编辑:在 Visual Studio 2015 中观察到此行为

【问题讨论】:

  • 您在两种情况下都使用了相同的优化级别,对吧?
  • @n.caillou 是的,我已经运行了优化和不优化两种情况。
  • @FrançoisAndrieux:更新了我的答案以涵盖 VS2015 行为

标签: c++ c++11 visual-c++ visual-studio-2015 constexpr


【解决方案1】:

gcc.godbolt.org 表明您的代码已经完全优化了 gcc 7clang 3.9,使用了 -std=c++11 -O1 标志。

取消注释volatile 操作显然会生成汇编指令,但不会为skip_first_wordstr_len 生成指令。


您对 Visual Studio 的看法是正确的:使用 CL 19 on gcc.beta.godbolt.org 表明正在为以下对象生成程序集:

constexpr auto foo = skip_first_word("Hello, World!");
constexpr auto foo_size = str_len(foo);

这似乎是一个编译器实现缺陷,因为 constexpr 变量应该并且可以在编译时完全计算。 此外,这些变量正在 static_assert 内使用,即 保证在编译时进行评估。这似乎表明编译器不必要地为 skip_first_wordstr_len 生成程序集,即使它们从未在运行时上下文中使用。

手动内联代码如下...

static_assert(str_len(skip_first_word("Hello, World!")) == 6, "Wrong size");
static_assert(str_len(skip_first_word("Hello, World!")) != 7, "Wrong size");

...produces no extra assembly.

【讨论】:

    猜你喜欢
    • 2012-12-24
    • 2020-10-01
    • 1970-01-01
    • 2019-04-24
    • 1970-01-01
    • 1970-01-01
    • 2021-02-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多