Передача аргументов функциям с параметрами const: это быстрее?

рассмотрим, к примеру:

int sum(int a, int b)
{
    return a + b;
}

и

int sum(const int a, const int b)
{
    return a + b;
}

второй подход в целом быстрее?

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

Edit: на sum пример просто иллюстрирует мою точку зрения. Я не ожидаю, что в этом конкретном примере должны быть большие различия. Но интересно, если в более сложных ситуациях const модификатор внутри параметра функции может быть использован компилятор, чтобы сделать функцию быстрее. Я сомневаюсь, что компилятор всегда может определить, изменяется ли параметр внутри функции (отсюда мой 2-й вопрос ниже); поэтому я ожидаю, что когда он найдет const модификатор, он делает что-то другое, чем когда нет const модификатор.

вопрос: в общем случае функция будет быстрее, когда ее аргументы const, чем, когда их нет?

Вопрос 2: в общем, может Компилятор C (теоретически) всегда определяет, изменяется ли параметр функции внутри функции?

4 ответов


короткий ответ:

долгий ответ, нет, с доказательством.

я провел этот тест, пару раз, и не видел никакой разницы в реальном времени, на моем MacBook pro, скомпилированном с clang:

int add(int a, int b)
{
    return a + b;
}

const int cadd(const int a, const int b)
{
    return a + b;
}

int main (int argc, char * argv[])
{
#define ITERS 1000000000

    clock_t start = clock();
    int j = 0;
    for (int i = 0; i < ITERS; i++)
    {
        j += add(i, i + 1);
    }

    printf("add took %li ticks\n", clock() - start);

    start = clock();
    j = 0;
    for (int i = 0; i < ITERS; i++)
    {
        j += cadd(i, i + 1);
    }

    printf("cadd took %li ticks\n", clock() - start);

    return 0;
}

выход

add took 4875711 ticks
cadd took 4885519 ticks

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

вот сравненная сборка генерируется:

_add:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    movl    %edi, -4(%rbp)
    movl    %esi, -8(%rbp)
    movl    -4(%rbp), %esi
    addl    -8(%rbp), %esi
    movl    %esi, %eax
    popq    %rbp
    ret

_cadd:                                 
    .cfi_startproc    
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    movl    %edi, -4(%rbp)
    movl    %esi, -8(%rbp)
    movl    -4(%rbp), %esi
    addl    -8(%rbp), %esi
    movl    %esi, %eax
    popq    %rb

Итак, как вы можете видеть, есть без разницы между двумя. Передача аргумента как const - это только подсказка вызывающему данный довод не будут изменены, а по простому сценарию, как описано выше, не приведет ни к какому другому скомпилированную сборку.


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


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

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


хотя и поздно для партии, компилятор может поместить переменные, определенные как const, в сегмент/блок памяти только для чтения, так что если была предпринята попытка записать на адрес, с помощью некоторого указателя tomfoolery, запись в память вызовет исключение во время выполнения.

-- Джейми