1

测试了一个简单的 utf8 strlen 函数,很惊讶trunk clang 完全消除了它(gcc 没有):

static int strlenutf8(const char* s)
{
  int i = 0, l = 0;
  while (s[i])
  {
    if ((s[i] & 0xc0) != 0x80) l++;
    l++;
  }
  return j;
}

int main()
{
    return strlenutf8("bla");
}

clang++ -O3 -S -fverbose-asm:

main:                                   # @main
    .cfi_startproc
# BB#0:                                 # %entry
    movl    $3, %eax
    ret

这就像 D 的编译时函数评估。这在 C++ 中是否合法?

我的意思是说,他们一开始就发明了那个糟糕的constexpr肯定是有原因的。据我所知,它甚至不能在这里使用,因为它受到严格限制。

4

3 回答 3

3

constexpr仅对于常量表达式上下文(如模板参数推导)是必需的,但constexpr不能保证在编译时对函数进行评估。

优化 C++ 程序的黄金法则是as-if

本国际标准中的语义描述定义了一个参数化的非确定性抽象机。本国际标准对一致性实现的结构没有要求。特别是,它们不需要复制或模仿抽象机器的结构。相反,需要符合要求的实现来模拟(仅)抽象机的可观察行为,如下所述。

加上急需的脚注:

这个规定有时被称为“好像”规则,因为只要从可观察的行为中可以确定,只要结果是好像已经遵守了要求,实施就可以自由地忽略本国际标准的任何要求的程序。例如,如果一个实际的实现可以推断出它的值没有被使用并且没有产生影响程序可观察行为的副作用,那么它就不需要评估表达式的一部分。

有一个主要的BUT:具有副作用的复制构造函数(例如,它们增加“称为”计数变量或等效的“复制构造函数”)不需要包含在“as-if”中。这包括在12.8/31

当满足某些条件时,允许实现省略类对象的复制/移动构造,即使对象的复制/移动构造函数和/或析构函数具有副作用。在这种情况下,实现将省略的复制/移动操作的源和目标简单地视为引用同一对象的两种不同方式,并且该对象的销毁发生在两个对象本应被删除的较晚时间。在没有优化的情况下销毁。123 这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以结合起来消除多个副本):[...]

于 2013-04-24T15:31:50.543 回答
2

通过在编译时评估表达式,需要符合 C++ 的编译器来支持constexpr。as-if 规则允许constexpr表达式的编译时求值;由于您的函数没有(可见的)副作用,因此允许编译器忽略它。strlenutf8

于 2013-04-24T15:30:48.810 回答
2

你将如何编写一个符合标准的 C++ 程序来检测这种优化?如果想不出办法,优化也行(好吧,好吧,如果没有办法)。编译器不需要仅仅因为您可能会查看生成的代码而低效地做事。

于 2013-04-24T16:02:48.930 回答