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

Параметр функции или локальная переменная

Скажем, у меня есть цикл, который повторяется миллионы раз. Внутри этого цикла у меня есть вызов функции.

Внутри этой функции мне нужно оперировать некоторой временной переменной, созданной в самом начале. Теперь, какой из них лучше:

a) Создайте временную переменную в начале кода, инициализируйте ее в начале цикла и передайте ее как параметр функции

b) Создать только локальную временную переменную в начале вызываемой функции?

Является ли этот ответный вопрос? Я хотел бы знать, какой момент считается лучшей практикой, или какой из них быстрее.

4b9b3361

Ответ 1

Позвольте задать некоторые возможные определения для some_function(), функции, которую вы будете вызывать из своего цикла.

// Method 1
void some_function() {
    int temporary;

    // Use temporary
}

// Method 2
void some_function(int temporary) {
    // Use temporary
}

// Method 3
void some_function(int *temporary) {
    // Use *temporary
}

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

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

Метод 3 почти наверняка будет медленнее, поскольку доступ во временную память будет включать в себя уровень косвенности. Разделение указателя не является дешевой операцией по сравнению с доступом к локальному.

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

Ответ 2

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

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

Как уже упоминалось, передача указателя на локальную переменную приведет к "штрафу" за доступ к указателю для получения значения. Это может не иметь большого значения, но это почти наверняка имеет значение. Это, безусловно, должно быть в последнюю очередь. [Обратите внимание, что если переменная LARGE, накладные расходы на передачу копии функции могут все же быть хуже служебных указаний. Но если мы предположим, что это простой тип типа int или float, то указатель имеет заметные накладные расходы].

В любой момент, когда возникает вопрос о производительности, вы ОПРЕДЕЛЕННО должны оценивать ВАШ код. Спросить кого-то в Интернете может быть целесообразным, если есть выбор между алгоритмами сортировки или чем-то подобным, но если это случай "лучше делать то или это" в некоторых более тонких различиях, то различия часто маленький, а ваш конкретный компилятор будет иметь гораздо большее влияние, чем "что теоретически лучше".

Ответ 3

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

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

Третий вариант, который вы опускаете, - это использование глобальной переменной.

В случае случайности значение всегда является постоянным, тогда лучший ответ использует #define и скомпилирует его непосредственно в код как литерал.