it-roy-ru.com

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

Рассмотрим, например:

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

vs.

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

Второй подход вообще быстрее?

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

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

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

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

17
becko

Краткий ответ: Нет

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

Я провел этот тест пару раз и не увидел никакой разницы в реальном времени на моем 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 взял 4875711 тиков 
 cadd взял 4885519 тиков 

Однако эти времена действительно должны быть взяты с нуля, поскольку 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 является только подсказкой для вызывающей стороны, аргумент не будет изменен, и в простом сценарии, подобном описанному выше, не будет получена другая скомпилированная сборка.

15
Richard J. Ross III

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

8
David Grayson

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

- Джейми

0
Jamey Kirby

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

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

0
RolandXu