Хорошо ли использовать функции как можно больше?
Когда я читаю открытые исходные коды (коды Linux C), я вижу, что вместо выполнения всех операций над main()
используются многие функции, например:
int main(void ){
function1();
return 0;
}
void function() {
// do something
function2();
}
void function2(){
function3();
//do something
function4();
}
void function3(){
//do something
}
void function4(){
//do something
}
Не могли бы вы рассказать мне, какие плюсы и минусы использовать функции как можно больше?
- легко добавлять/удалять функции (или новые операции)
- читаемость кода
- эффективность источника (?), поскольку переменные в функциях будут уничтожены (если не выполняется динамическое распределение)
- может ли вложенная функция замедлить поток кода?
Ответы
Ответ 1
- Легко добавлять/удалять функции (или новые операции)
Определенно - также легко увидеть, где находится контекст для запуска/завершения операции. Это намного проще видеть, чем какой-либо произвольный диапазон строк в источнике.
Вы можете переусердствовать. Бывают случаи, когда наличие функции или ее отсутствие не влияет на линейную линейность, но делает ее читабельностью - и это зависит от того, является ли она положительной или нет.
Например, если вы сделали много операций с множеством бит, вы бы сделали:
some_variable = some_variable | (1 << bit_position)
функция? Помогло бы?
- Эффективность источника (?) из-за переменных в разрушаемых функциях (если динамическое распределение не выполняется)
Если источник разумный (как и в, вы не используете имена переменных за своим реальным контекстом), тогда это не имеет значения. Компилятор должен точно знать, где останавливается использование значения, и где его можно игнорировать/уничтожать.
- Может ли вложенная функция замедлять поток кода?
В некоторых случаях, когда псевдонимы адресов не могут быть правильно определены, он может. Но в большинстве программ это не имеет большого значения. К тому времени, когда это начинает иметь значение, вы, вероятно, собираетесь проходить через ваше приложение с профилировщиком и обнаруживать проблематичные горячие точки в любом случае.
В наши дни компиляторы неплохо работают при инлайн-функциях. Вы можете доверять им, чтобы сделать хотя бы достойную работу, чтобы избавиться от всех случаев, когда накладные расходы вызова сопоставимы с самой длиной функции. (и многие другие случаи)
Ответ 2
Эта практика использования функций действительно важна, так как увеличивается количество написанного вами кода. Эта практика разделения функций улучшает гигиену кода и упрощает ее чтение. Я где-то читал, что на самом деле нет смысла кода, если он доступен только для чтения (в некоторых ситуациях это нормально, я предполагаю). Если вы хотите, чтобы ваш код работал, он должен быть ремонтопригодным, а ремонтопригодность создается путем создания функций в самом простом смысле. Также представьте, где ваша кодовая база превышает 100 тысяч строк. Это довольно часто, и представьте, что все это в главной функции. Это было бы абсолютным кошмаром для поддержания. Разделение кода на функцию помогает создавать степени разделимости, поэтому многие разработчики могут работать на разных частях кода. Так что в основном короткий ответ - да, полезно использовать функции, когда это необходимо.
Ответ 3
Функции должны помочь вам структурировать ваш код. Основная идея заключается в том, что, когда вы определяете какое-то место в коде, которое делает что-то, что можно описать согласованным, автономным способом, вы должны подумать о его включении в функцию.
Плюсы:
- Повторное использование кода. Если вы выполняете много раз некоторую последовательность операций, почему бы вам не написать ее один раз, использовать ее много раз?
- Читаемость: гораздо легче понять
strlen(st)
чем while (st[i++] != 0);
- Корректность: код предыдущей строки на самом деле ошибочен. Если он разбросан вокруг, возможно, вы даже не увидите эту ошибку, и если вы исправите ее в одном месте, ошибка останется где-то в другом месте. Но, учитывая этот код внутри функции с именем
strlen
, вы будете знать, что он должен делать, и вы можете исправить его один раз.
- Эффективность: иногда, в определенных ситуациях, компиляторы могут делать лучшую работу при компиляции кода внутри функции. Вы, вероятно, не будете знать это заранее.
Минусы:
- Разделение кода на функции только потому, что это хорошая вещь, это не очень хорошая идея. Если вам трудно дать функции доброе имя (на вашем родном языке, а не только на C), это подозрительно.
doThisAndThat()
- это, вероятно, две функции, а не одна. part1()
просто неверно.
- Вызов функции может стоить вам во время выполнения и в стеке. Это не так тяжело, как кажется, большую часть времени вам не нужно заботиться, но оно есть.
- При злоупотреблении это может привести к тому, что многие функции выполняют частичную работу и делегируют другие части оттуда туда. слишком много аргументов могут затруднять читаемость.
Существуют в основном два типа функций: функции, выполняющие последовательность операций (в некоторых контекстах они называются "процедурами" ) и функциями, которые выполняют какую-то форму вычисления. Эти два типа часто смешиваются в одной функции, но это помогает запомнить это различие.
Существует другое различие между видами функций: те, которые сохраняют состояние (например, strtok
), те, которые могут иметь побочные эффекты (например, printf
), и те, которые являются "чистыми" (например, sin
). Функция типа strtok
по существу представляет собой особый вид другой конструкции, называемой Object в объектно-ориентированном программировании.
Ответ 4
Вы должны использовать функции, которые выполняют одну логическую задачу каждый, на уровне абстракции, что облегчает логическую проверку функции каждой функции. Например:
void create_ui() {
create_window();
show_window();
}
void create_window() {
create_border();
create_menu_bar();
create_body();
}
void create_menu_bar() {
for(int i = 0; i < N_MENUS; i++) {
create_menu(menus[i]);
}
assemble_menus();
}
void create_menu(arg) {
...
}
Теперь, что касается создания пользовательского интерфейса, это не совсем так, как это можно было бы сделать (вы, вероятно, захотите передать и вернуть различные компоненты), но логическая структура - это то, что я пытаюсь подчеркивать. Разделите свою задачу на несколько подзадач и сделайте каждую подзадачу своей собственной функцией.
Не пытайтесь избежать функций для оптимизации. Если это разумно сделать, компилятор сделает их для вас; если нет, накладные расходы по-прежнему минимальны. Усиление читаемости, которое вы получаете от этого, намного важнее любой скорости, которую вы могли бы получить от размещения всего в монолитной функции.
Что касается вашего титульного вопроса, "как можно больше", нет. В пределах причины достаточно, чтобы увидеть, что каждая функция делает на комфортном уровне абстракции, не меньше и не более.
Ответ 5
Одно условие, которое вы можете использовать: если часть кода будет повторно использоваться/перезаписана, тогда поместите ее в функцию.
Ответ 6
Думаю, я думаю о таких функциях, как legos. У вас есть сотни небольших кусочков, которые вы можете объединить в целое. В результате всех хорошо продуманных родовых небольших кусочков вы можете сделать что угодно. Если бы у вас был единственный лего, похожий на весь дом, вы не могли бы использовать его, чтобы построить самолет или поезд. Точно так же один огромный фрагмент кода не так полезен.
Функции - это ваши кирпичи, которые вы используете при разработке своего проекта. Хорошо выбранное разделение функциональности на небольшие, легко проверяемые, самодостаточные "функции" упрощают создание и уход за всем вашим проектом. Их преимущества WAYYYYYYY вывешивают любые возможные проблемы с эффективностью, которые вы можете себе представить.
Честно говоря, искусство кодирования любого значимого проекта заключается в том, как вы разбиваете его на более мелкие части, поэтому функции являются ключевыми для этого.