2013-06-27 4 views
15

Когда я прочитал коды с открытым исходным кодом (коды 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 
} 

Не могли бы вы сказать мне, какие плюсы и минусы использования функций как можно больше?

  • легко добавлять/удалять функции (или новые операции)
  • читаемость кода
  • эффективности
  • источника (?), Как переменные в функциях будут уничтожены (если динамическое распределение не сделано)
  • будет ли вложенная функция замедлять поток кода?
+26

Да. Код становится легче читать. Да. Вы можете легко обновить. Да. Он более универсален. Фактически, 'yes' должно было быть функцией в этом комментарии. – fedorqui

+3

@fedorqui ваш комментарий выглядит намного лучше, чем вопрос: = D – haccks

+2

Это всегда * возможно * разбить вещь на большее количество функций. В какой-то момент вам нужно остановиться, поэтому я бы сказал «нет, нехорошо использовать функции как можно больше»;) Но короткие, слабые, четко определенные функции всегда хороши. –

ответ

11
  • легко добавлять/удалять функции (или новые операции)

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

  • читаемость кода

Вы можете переусердствовать. Бывают случаи, когда наличие функции или ее отсутствие не влияет на линейную линейность, но делает ее читабельностью - и это зависит от того, является ли она положительной или нет.

Например, если вы сделали много набор-битных операций, вы бы сделать:

some_variable = some_variable | (1 << bit_position) 

функцию? Помогло бы это? Эффективность

  • Источника (?) из-за переменные в функциях уничтожаются (если динамическое распределение не сделано)

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

  • Может ли вложенная функция замедлить поток кода?

В некоторых случаях, когда псевдонимы адресов не могут быть правильно определены, он может. Но в большинстве программ это не имеет большого значения. К тому времени, когда это начинает иметь значение, вы, вероятно, собираетесь проходить через ваше приложение с профилировщиком и выявлять проблемные горячие точки.

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

+2

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

+2

Он также делает возможным модульное тестирование/упрощение и упрощает проверку кода в целом, когда у вас есть небольшие функции, выполняющие отдельные задачи. Подтверждение того, что одна маленькая функция делает одну вещь правильной, проще и надежнее, чем проверка того, что одна большая функция делает 200 вещей прав. –

+4

Не должно быть 'some_variable | = 1 << bit_position;'? –

0

Одно условие, которое вы можете использовать: если часть кода будет повторно использована/переписана, тогда введите ее в функцию.

+4

Нет. Есть намного больше. – Elazar

+0

@ Elazar Правильно, но он сказал * One * состояние. Так что это совершенно правильно, но довольно мало. – glglgl

+1

Хорошо, мое плохое. не следует использовать слишком тяжелое слово, чтобы описать его только сейчас. Я только что отредактировал его. – Neoh

4

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

+3

Полностью согласен. И: в определенном смысле функции очень похожи на абзацы ... ;-) – alk

+0

Не только абзацы: те, у кого есть заголовок раньше. 'как я сказал в разделе G 'или, может быть,« см. »часть 2:« Что может быть не так »для деталей» – Elazar

1

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

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) { 
    ... 
} 

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

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

Что касается вашего титульного вопроса, «как можно больше», нет. В пределах разума достаточно увидеть, что каждая функция делает на комфортном уровне абстракции, не меньше и не больше.

0

Думаю, я думаю о функциях, подобных legos. У вас есть сотни небольших кусочков, которые вы можете объединить в целое. В результате всех хорошо продуманных родовых небольших кусочков вы можете сделать что угодно. Если бы у вас был единственный лего, похожий на весь дом, вы не могли бы использовать его, чтобы построить самолет или поезд. Точно так же один огромный фрагмент кода не так полезен.

Функции - это ваши кирпичи, которые вы используете при проектировании своего проекта. Хорошо выбранное разделение функциональности на небольшие, легко проверяемые, самодостаточные «функции» упрощают создание и уход за всем вашим проектом. Их преимущества WAYYYYYYY - взвешивают любые возможные проблемы с эффективностью, которые вы можете себе представить.

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

3

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

Плюсы:

  • повторное использование кода. Если вы выполняете много раз некоторую последовательность операций, почему бы вам не написать ее один раз, использовать ее много раз?
  • Читаемость: это гораздо легче понять, чем strlen(st)while (st[i++] != 0);
  • корректности: код в предыдущей строке на самом деле глючит.Если он разбросан вокруг, возможно, вы даже не увидите эту ошибку, и если вы исправите ее в одном месте, ошибка останется где-то в другом месте. Но, учитывая этот код внутри функции с именем strlen, вы будете знать, что он должен делать, и вы можете исправить ее один раз.
  • Эффективность: иногда, в определенных ситуациях, компиляторы могут выполнять лучшую работу при компиляции кода внутри функции. Однако вы, вероятно, не будете знать это заранее.

Минусы:

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

Существует в основном два типа функций: функции, выполняющие последовательность операций (в некоторых случаях они называются «процедурами») и функциями, которые выполняют какую-либо форму вычисления. Эти два типа часто смешиваются в одной функции, но это помогает запомнить это различие.

Существует еще одно различие между видами функций: Те, которые держат состояние (как strtok), те, которые могут иметь побочные эффекты (как printf), и те, которые являются «чистыми» (как sin). Функция типа strtok по существу представляет собой особый вид другой конструкции, называемой Object в объектно-ориентированном программировании.

+0

Я слышал, что 'strtok()' вызвал много вещей (большинство из них несовместимы, например, «паразит»), но я никогда не видел, чтобы это воспринималось как образец объекта в ООП. Вы уверены, что? –

+1

@JonathanLeffler У этого есть идентичность (singleton, так что это тривиально), состояние (вы знаете, что любая функция делает, но это тривиально для других) и поведение (есть в основном два сообщения, которые вы можете передать ему). Идентичность + положение + = behvior объекта; здесь только тривиальность. (Да, есть много других определений, к которым это не обязательно соответствует.) – Elazar