Подтвердить что ты не робот

Выполняются ли математические функции постоянных выражений во время компиляции?

Я стараюсь использовать математические функции постоянных выражений для удобства и когерентности (т.е. log(x)/log(2) вместо log(x)/0.3...). Поскольку эти функции фактически не являются частью самого языка, они не определены в math.h (только объявлено), будут ли константы вычисляться в момент компиляции или будут ли они расходомированы во время выполнения?

4b9b3361

Ответ 1

Некоторые компиляторы будут оценивать их во время компиляции, но это поведение не гарантируется (и это может также вызвать проблемы). Вам нужно будет проверить свой компилятор и посмотреть, что он делает.

Обратите внимание, что во многих системах log(2) доступен из макроса M_LN2 в <math.h>.

Ответ 2

Это зависит от флагов компилятора и оптимизации. Как указывает @AndrewyT, GCC имеет возможность указать, какие функции являются постоянными и чистыми с помощью атрибутов, и в этом случае ответ положительный, он будет встраивать результат, как вы можете легко проверить:

$ cat constant_call_opt.c 
#include <math.h>

float foo() {
        return log(2);
}

$ gcc -c constant_call_opt.c -S

$ cat constant_call_opt.s 
        .file   "constant_call_opt.c"
        .text
.globl foo
        .type   foo, @function
foo:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $4, %esp
        movl    $0x3f317218, %eax
        movl    %eax, -4(%ebp)
        flds    -4(%ebp)
        leave
        ret
        .size   foo, .-foo
        .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
        .section        .note.GNU-stack,"",@progbits

нет вызова функции там, просто загружает константу (0x3f317218 == 0.69314718246459961 == log(2))

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

Ответ 3

Обычно они вычисляются во время выполнения (см. другие ответы на вопрос о том, как их встроить), хотя я бы не обязательно использовал слово "расточительно", если их не было много, и/или код был выполнен много раз.

Вместо того, чтобы просто вводить постоянное значение, создайте переменную #define или const, которая выражает то, что означает значение (PI, LOG_2 и т.д.), и используйте это вместо этого.

Например:

#define LOG_2 0.30102999566

Это не делает никаких вычислений, и вы можете указать значение, которое вы хотите или можете управлять с учетом вашей среды (32-разрядная версия - 64 бит).

Ответ 4

Это зависит. Если компилятор может выполнить математику точно так, как это было бы сделано во время выполнения, и если выполняется оптимизация времени ссылки, и если библиотека хранится в какой-то промежуточной форме, то да, это можно сделать.

Большинство компиляторов не делают все это.

Ответ 5

В случае библиотечных функций некоторый компилятор может реализовать эти функции как встроенные, что означает, что компилятор достаточно знает о функциях, которые заменяют вызов константой во время компиляции. Будет ли это сделано, это зависит от компилятора. На практике я часто замечаю, что некоторые компиляторы неохотно предварительно вычисляют выражения с плавающей запятой во время компиляции, даже если они не связаны с вызовами функций.

В общем случае обычно они не будут вычисляться и не могут вычисляться во время компиляции, предполагая, что компилятор просто не знает достаточно об этих функциях, чтобы иметь возможность рассчитать их во время компиляции. Возможно, у них есть некоторые заметные побочные эффекты во время работы?

Некоторые компиляторы могут иметь нестандартные расширения, зависящие от компилятора, которые позволяют пользователю предоставлять дополнительную информацию о функциях компилятору, чтобы компилятор мог лучше оптимизировать вызовы функций и даже выяснить, может ли данный вызов быть заменен на предварительный расчет времени компиляции. Например, компилятор GCC поддерживает такую ​​функцию attributes (GCC-специфическое расширение) как const и pure. Если аргументы известны во время компиляции, вызов функции с атрибутом const может быть теоретически заменен на предварительный расчет времени компиляции. Хотя я не могу сказать, сможет ли GCC на самом деле это сделать.

В С++ (хотя ваш вопрос с тегом C) язык запланированной новой функцией является спецификатором объявления constexpr, который выполняет аналогичную цель и должен иметь эффект, который вы описываете.

Ответ 6

Это происходит во время выполнения, так как код для функции становится доступным только на этапе связывания (который происходит после этапа компиляции).

Чтобы оптимизировать шаг, используйте глобальную переменную, которую вы инициализируете, прежде чем использовать ее.