У меня есть следующий код на C ++ здесь:
#include <iostream>
int main(int argc, const char * argv[])
{
goto line2;
line1:
std::cout << "line 1";
goto line3;
line2:
std::cout << "line 2";
goto line1;
line3:
std::cout << "line 3";
goto line4;
line4:
std::cout << "Hello, World!\n";
return 0;
}
Если я создал большую программу, скажем, 10 000 строк кода, и решил, что никогда не буду использовать функции, которые сам пишу, я использую только операторы goto. Я использую только глобальные переменные. Я немного сумасшедший с точки зрения лучших практик, но это для очень конкретной цели. Вопрос состоит в том, будет ли это эффективным, чтобы прыгать с заявлениями goto? Что делать, если у меня 1000 ярлыков?
Переводят ли операторы goto непосредственно в машинный код, который сообщает компьютеру просто JUMP по другому адресу памяти? Это более низкая стоимость в машине, чтобы прыгать, как эта, по сравнению со стоимостью вызова функции?
Я хочу знать, как я хочу написать очень эффективную программу для выполнения некоторых вычислений, и мне нужно быть очень эффективным, не прибегая к сборке / машинному коду.
Нет необходимости говорить мне, что это плохая идея с точки зрения обслуживания, понятности кода, лучших практик, я это прекрасно осознаю, я просто хочу получить ответ на вопрос. Я не хочу спорить между тем, хорошо ли использовать вызовы функций или хорошо использовать goto.
Чтобы прояснить вопрос, я обеспокоен в этом случае использованием gotos только с программой из 10000 строк, чтобы сравнить ее с традиционной программой, использующей функции. Существует несколько способов сравнить и сопоставить эти две программы, например, как будет работать кэш процессора. Какой вид экономии это даст без вызовов функций. Без стека вызовов, как это повлияет на кэш ЦП, поскольку кэш-память ЦП обычно сохраняет стек закрытым. Был бы для этого случай, когда он может иметь отрицательный удар по производительности из-за неправильного использования кэша. Какова фактическая стоимость вызова функции по сравнению с скачком с точки зрения эффективности времени. Есть много способов сравнить и сопоставить два стиля программирования с точки зрения эффективности.
Переводят ли операторы goto непосредственно в машинный код, который сообщает компьютеру просто JUMP по другому адресу памяти?
Да.
Это более низкая стоимость в машине, чтобы прыгать, как эта, по сравнению со стоимостью вызова функции?
Да.
Однако, когда компилятор видит вызов функции, он не должен фактически генерировать код для вызова функции. Он может взять все функции и вставить их туда, где был вызов, даже не прыгнув. Так что было бы более эффективно вызывать функцию!
Кроме того, чем меньше ваш код, тем он будет эффективнее (вообще говоря), поскольку он с большей вероятностью помещается в кэш процессора. Компилятор может видеть это и может определить, когда функция мала, и лучше встроить ее, или когда она большая и лучше отделить ее и сделать ее реальной функцией, чтобы сгенерировать самый быстрый код (если он настроен на генерацию). самый быстрый код из возможных). Вы не можете видеть это, поэтому вы угадываете и, вероятно, угадываете неправильно.
И это только некоторые из очевидных. Есть так много других оптимизаций, которые может сделать компилятор. Пусть компилятор решит. это умнее тебя. Это умнее меня. Компилятор знает все. Серьезно, Ктулху, вероятно, является компилятором.
Вы сказали не, но я собираюсь сказать это: я настоятельно советую вам профиль Ваш код, прежде чем принять решение, я почти гарантирую, что это не стоит вашего времени. Компилятор (большинство из которых почти умны) может генерировать как быстрый или быстрый код с регулярными вызовами функций, не говоря уже о аспекте обслуживания.
Переводят ли операторы goto непосредственно в машинный код, который
говорит компьютеру просто перепрыгнуть на другой адрес памяти?
Довольно много.
Это более низкая стоимость в машине, чтобы прыгать, как это, когда
по сравнению со стоимостью вызова функции?
Вызов функции сделает довольно похожий переход, но прежде чем вы сможете выполнить переход, вы должны настроить новый кадр стека для новой функции, передать параметры в соответствии с соглашениями о вызовах и в конце настроить любой возврат цени и раскрути. Да, наверное, быстрее этого не делать.
Я немного ненормальный
Да.
Да, машинный код, сгенерированный из goto, будет прямым JUMP. И это, вероятно, будет быстрее, чем вызов функции, потому что ничего не нужно делать со стеком (хотя вызов без передаваемых переменных будет оптимизирован таким образом, что он может быть таким же быстрым).
И Бог поможет вам, когда что-то не работает с этим кодом. Или когда кто-то другой должен поддерживать это.
1) Вопрос состоит в том, будет ли это эффективным, чтобы прыгать с заявлениями goto? Что делать, если у меня 1000 ярлыков?
Из вашего маленького примера с 4 goto
ярлыки, куда вы прыгаете назад и вперед, нет, это не эффективно с точки зрения производительности. Чтобы избежать издержек в механизме вызова функций, этот метод отключает многие другие оптимизации, которые компилятор автоматически сделает для вас. Я не перечисляю их, но этот стоит прочтения.
2) Переводят ли операторы goto непосредственно в машинный код, который сообщает компьютеру просто JUMP по другому адресу памяти?
ДА (как правильно указали другие)
3) Это более низкая стоимость в машине, чтобы прыгать, как эта, по сравнению со стоимостью вызова функции?
ДА, только если ваш компилятор доисторический и не имеет встроенного механизма оптимизации. Иначе НЕТ.
И я не говорю о лучших практиках ..
Трудно ответить на ваш запрос точно, это зависит от сложности вашей программы и использования операторов goto внутри.
Оператор goto эквивалентен инструкции безусловного перехода (например, jmp). Объем goto будет в файле.
Ричи предлагает избегать использования оператора goto, и если вы все еще хотите / должны использовать оператор goto, то используйте его в подходе сверху вниз, не используйте его в подходе снизу вверх.
Ну, это детали учебника.
Практически вы должны быть очень уверены, где использовать оператор goto, и после перехода goto, где будет происходить поток вашей программы, в противном случае, поскольку вы упомянули 1000 операторов goto, вам будет также трудно определить ход выполнения программы, забудьте о других. Поэтому дальнейшее улучшение вашей программы будет очень и очень сложным.
Есть много других средств, таких как циклы, условные операторы, операторы break и continue, функции и т. Д., Чтобы помочь вам избежать таких проблем.
Надеюсь, поможет…..
Короче говоря, операторы GoTo могут быть эффективными, но именно так они и используются. По словам Герберта Шильдта (C ++ с первого этажа), «Не существует ситуаций программирования, которые требуют использования оператора goto — это не тот элемент, который необходим для завершения языка». В конечном счете, основная причина, по которой многим программистам не нравится это утверждение, заключается в том, что операторы goto имеют тенденцию загромождать ваш код и / или затруднять его чтение, поскольку, согласно названию, gotos может перемещаться с места на место. С учетом вышесказанного бывают ситуации, когда оператор goto может уменьшить беспорядок, а также сделать код более эффективным, но это полностью зависит от того, как вы их используете и от контекста, в котором они используются. Лично я бы рекомендовал использовать вызовы функций. , в отличие от нескольких утверждений goto; другие могут не согласиться.