constexpr: g cc пытается усвоить constexpr, чем clang - PullRequest
0 голосов
/ 22 января 2020

Я использую Godbolt, чтобы увидеть сгенерированный код с g cc и clang.

Я пытался реализовать до djb2 га sh.

g cc всегда старается всегда пробовать вычислить функцию constexpr.

clang оценивает constexpr, только если переменная является constexpr.

Давайте рассмотрим пример:

constexpr int djb2(char const *str)
{
    int hash = 5381;
    int c = 0;

    while ((c = *str++))
    hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
        return hash;
}

int main()
{
    int i = djb2("hello you :)");
}

С В этом примере g cc оценивает время компиляции i. Но лязг во время выполнения.

Если я добавлю constexpr к i, то clang выполнит оценку и во время компиляции.

Знаете ли вы, что стандарт говорит что-то об этом?

РЕДАКТИРОВАТЬ: спасибо всем. Итак, как я понимаю, без constexpr компилятор делает то, что хочет. С constexpr компилятор вынужден вычислять константу.

1 Ответ

6 голосов
/ 22 января 2020

Ваша программа имеет неопределенное поведение.

Сдвиг hash << 5 переполнится, что имеет неопределенное поведение для целочисленных типов со знаком до C ++ 20.

В частности, это означает, что вызов вашей функции никогда не может привести к константному выражению, которое вы можете проверить, добавив constexpr к вашему объявлению i. Затем оба компилятора должны будут диагностировать неопределенное поведение и сообщат вам об этом.

Дайте hash тип без знака, и ваш код будет на самом деле иметь четко определенное поведение, а выражение djb2("hello you :)" будет фактически константное выражение, которое может быть вычислено во время компиляции, при условии, что вы используете C ++ 14 или более позднюю версию (l oop не было разрешено в функции constexpr в C ++ 11.).

Для этого по-прежнему не требуется, чтобы компилятор действительно выполнял оценку во время компиляции, но затем вы можете форсировать его, добавив constexpr к объявлению i.

" Force"здесь относительно. Из-за правила как-будто и из-за отсутствия наблюдаемой разницы между вычислением во время компиляции и во время выполнения, компилятору по-прежнему не требуется технически выполнять вычисления только во время компиляции. -time, но он требует, чтобы компилятор проверил весь расчет на достоверность, что в основном совпадает с его оценкой, поэтому для компилятора было бы неразумным повторять оценку во время выполнения.

Аналогично " может оцениваться во время компиляции"также относительно. Опять же по тем же причинам, что и выше, компилятор может по-прежнему выбирать вычисления во время компиляции, даже если они не являются константным выражением, если не будет заметных различий в поведении. Это чисто вопрос качества оптимизатора. В вашем конкретном случае c программа имеет неопределенное поведение, поэтому компиляторы могут в любом случае делать то, что они хотят.

...