Хорошо ли использовать функции как можно больше?

Когда я читаю открытые исходные коды (коды 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 вывешивают любые возможные проблемы с эффективностью, которые вы можете себе представить.

Честно говоря, искусство кодирования любого значимого проекта заключается в том, как вы разбиваете его на более мелкие части, поэтому функции являются ключевыми для этого.