LINUX.ORG.RU
Ответ на: комментарий от FeyFre

Кстати, вопрос.

Неоднократно замечал, что некоторые люди намеренно разбивают функцию на прототип+тело, даже если можно просто функцию в одном месте определить. Зачем вы это делаете?

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Можно не париться с порядком следования определений функций, если декларации прототипов выше всех тел.

Bfgeshka ★★★★★
()
Ответ на: комментарий от Bfgeshka

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

Получается, это делают, чтобы удобнее было код писать?

anonymous> чтобы main был выше всех и его потом не пришлось искать.

Но ведь если все остальные функции выше main, то main — последняя функция. И её тоже не приходится искать.

Да, нужно будет найти начало. Но ведь и с прототипами сверху начало main не обязательно влезет в первые несколько экранов. Там перед ней глобальные переменные, типы, макросы, прототипы.

i-rinat ★★★★★
()
Ответ на: комментарий от FeyFre

Мда, у меня оказывается была мааленькая опечатка на которую я долго смотрел и не видел. Вот черт, надо больше спать. Спасибо.

normann ★★★
() автор топика
typedef enum blablabla_e
{
blabla1,
blabla2
} blablabla_t;
mittorn ★★★★★
()
Ответ на: комментарий от i-rinat

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

Это вообще нехорошо и плохая практика. А просто использовать прототипы это вполне ок, потому что, опять же, порядок становится не важен. Тогда можно организовывать сами тела функций - например, отсортировать по алфавиту и тогда искать удобно будет. Или ещё как хочется, без разницы.

В много файловых софтинах, где часто идут пары .c + .h с одним именем, часто определяют прототипы, если нужно включать заголовочный файл в несколько файлов. Если его включить в свой собственный, то будет где-то то же самое - прототипы будут в самом начале и на расположение определений уже начхать.

Короче говоря, архитектура такая довольно удобная, но совсем не обязательная к применению.

Bfgeshka ★★★★★
()
Ответ на: комментарий от i-rinat

Зачем вы это делаете?

Видимо по той же причине, по которой вместо

class Foo
{
public:
  void foo()
  {
     // do something useful
  }
};

пишут

class Foo
{
public:
  void foo();
};

inline void Foo::foo()
{
   // do something useful
}

Полагаю это из-за:

  • такой стиль кода;
  • так интерфейс получается чище;
andreyu ★★★★★
()
Ответ на: комментарий от i-rinat

Получается, это делают, чтобы удобнее было код писать?

Так удобнее потом собирать заголовочные файлы. А ещё всякие расширения типа __restrict/ __THROW или там __attribute__((..)) гораздо удобнее загромождать в описании, а не в реализации функции.

vodz ★★★★★
()
Ответ на: комментарий от Bfgeshka

Это вообще нехорошо и плохая практика.

Да ладно?!

В много файловых софтинах, где часто идут пары .c + .h с одним именем, часто определяют прототипы, если нужно включать заголовочный файл в несколько файлов. Если его включить в свой собственный, то будет где-то то же самое - прототипы будут в самом начале и на расположение определений уже начхать.

Я про внутренние функции единицы компиляции. Они static, и снаружи не видны. Их вообще может в сгенерированном коде не остаться, ведь компилятор не обязан оформлять их отдельными функциями, которые можно вызывать.

i-rinat ★★★★★
()
Ответ на: комментарий от andreyu

Видимо по той же причине, по которой вместо <...> пишут <...>

Тут публичный интерфейс, это другое. В Си в таком случае прототипы будут в отдельном файле.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Я про внутренние функции единицы компиляции. Они static, и снаружи не видны. Их вообще может в сгенерированном коде не остаться, ведь компилятор не обязан оформлять их отдельными функциями, которые можно вызывать.

Кому как почешется. Чем больше функций, тем логичнее такая техника.

Да ладно?!

По секрету скажу - да, это так.

Bfgeshka ★★★★★
()
Ответ на: комментарий от Bfgeshka

Короче говоря, архитектура такая довольно удобная, но совсем не обязательная к применению.

Это не архитектура, а стиль. Если перед умными функциями будут нагромождение тупых мелких многочисленныхз вспомогательных функций, код зачастую получается не для чтения/правки, а для упихивания в один файл с минимальным количеством строк, типа busybox-а :)

А еще бывают всякие парсеры, где функции вызывают друг друга рекурсивно-взаимно.

vodz ★★★★★
()
Ответ на: комментарий от Bfgeshka

Чем больше функций, тем логичнее такая техника.

Регулярно вычищаю мусор, который остаётся из-за такой техники. Так что вижу минусы, но не вижу плюсов.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Так что вижу минусы, но не вижу плюсов.

Да у вас с чувствами что-то явно не то. Такой стиль принят, например, в BSD и вообще встречается чаще, чем следовало бы.

vodz ★★★★★
()
Ответ на: комментарий от vodz

Да у вас с чувствами что-то явно не то.

Хо-хо-хо. Что я вижу? Переход на личности?

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Так что вижу минусы, но не вижу плюсов.

Тогда просто не используй такой подход. Если наткнёшься по плюс, то всё поймёшь и начнёшь сам так делать, а если не наткнёшься, то просто сэкономишь на писанине.

JacobTwoTwo
()
Ответ на: комментарий от i-rinat

1) Да, как аноним сказал, я люблю когда тело main первое в файле.
2) И случай когда кодю сложный алгоритм, я начинаю писать тело функций самого верхнего уровня, а потом кодю вспомогательные. Тут без прототипов сверху не обойтись, да и полезно видеть сигнатуры перед глазами. Во время промежуточных компиляций, компилятору хватит прототипа. Ну и в силу привычки так делаю везде.


ЗЫ: да, а ещё я привык писать int main(int argc, char *argv[], char* env)

FeyFre ★★★★
()
Ответ на: комментарий от i-rinat

некоторые люди намеренно разбивают функцию на прототип+тело, даже если можно просто функцию в одном месте определить. Зачем вы это делаете?

Имхо, когда подряд идут прототипы типа

type1 f1(type2 arg1, type3 arg2);
type2 f2(type2 arg1, type4 arg2, type4 arg3);
// ...

а за ними длинные определения, то удобнее читать, независимо, вначале main или в конце.

А если кто-то оставляет прототип после удаления тела, так это просто неаккуратность. А чтобы неаккуратно писать, прототипы не нужны. Можно и ненужные переменные оставлять, и константы, и много чего ещё. Дурное дело - не хитрое. :-)

aureliano15 ★★
()
Ответ на: комментарий от JacobTwoTwo

Тогда просто не используй такой подход.

Я не единственный, кто пишет код.

а если не наткнёшься, то просто сэкономишь на писанине.

Экономия на писанине — вообще не аргумент. Разве что для write-only кода.

i-rinat ★★★★★
()

всегда можно смоделировать возвращая несколько значений и конструировать из них требуемое

anonymous
()
Ответ на: комментарий от i-rinat

юзать extern? Иметь API reference прям в include файле? Да много причин так делать. Порой же просто удобнее накидать примерное api типа спроектировать что как и чем будет обрабатываться, написать над каждым прототипом короткую доку в комментариях, а потом не спеша реализовывать эти самые функции. + Размещать реализацию под main. А ещё это очень удобно когда смотришь в чужой код.

Dron ★★★★★
()
Последнее исправление: Dron (всего исправлений: 3)
Ответ на: комментарий от i-rinat

Да, нужно будет найти начало. Но ведь и с прототипами сверху начало main не обязательно влезет в первые несколько экранов. Там перед ней глобальные переменные, типы, макросы, прототипы.

Перенести в include.h такое нужно

Dron ★★★★★
()
Ответ на: комментарий от i-rinat

Можно не париться с порядком следования определений функций, если декларации прототипов выше всех тел.

плюсирую, именно для этого

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от Dron

А ещё это очень удобно когда смотришь в чужой код.

Сначала ты сталкиваешься с функцией, которая использует кучу других функций, о работе которых ты не знаешь. При чтении всё равно придётся прыгать туда-сюда по файлу. Ещё ведь не факт, что автор кода хорошо продумал названия функций. Конечно, если продумал, то код читается как текст.

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

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

ри чтении всё равно придётся прыгать туда-сюда по файлу. Ещё ведь не факт, что автор кода хорошо продумал названия функций.

Да, тут не поспорить, как пример это dwm.c там в начале идуст структуры и прочее, а за ними декларации всех функций, с одной стороны удобно, с другой всё равно надо туда сюда вертеть код, но в подобных случаях лично мне всё же лучше так чем когда каждая функция без декларации реализована одна за другой, я часто забываю что принимает функция и что возвращает, лично мне удобно когда без навигации по коду можно просто посмотреть кучу деклараций в одном месте, например открыв их сплитом в в редакторе. К тому же я часто сам дописываю над декларациями микродоки для себя когда что-то не очевидное и надо оставить заметку для себя. А в целом да, сишные исходники настолько разнообразны в плане оформления и структуры что так или иначе всё зависит от того написано всё махом или же разработчик протекционист и расфасовал всё структурировано и единообразно, пусть плохо, но единообразно )) Как повезёт )

Dron ★★★★★
()
Ответ на: комментарий от i-rinat

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

hotpil ★★★★
()
Ответ на: комментарий от vromanov

Вопрос был «зачем», а не «почему». Другими словами, в чём смысл, а не в чём причина.

i-rinat ★★★★★
()
Ответ на: комментарий от Dron

Да, тут не поспорить, как пример это dwm.c там в начале идуст структуры и прочее, а за ними декларации всех функций ...

Да ну, ориентироваться на этих suckless без толку. У них там какая-то религия, а не программирование.

hotpil ★★★★
()
Ответ на: комментарий от hotpil

И часто у тебя static функции в библиотеку переезжают? Даже если уже делаешь библиотеку, будут внутренние функции.

i-rinat ★★★★★
()
Ответ на: комментарий от vodz

А еще бывают всякие парсеры, где функции вызывают друг друга рекурсивно-взаимно.

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

Iron_Bug ★★★★★
()
Ответ на: комментарий от i-rinat

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

den73 ★★★★★
()
Последнее исправление: den73 (всего исправлений: 1)
Ответ на: комментарий от den73

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

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Структуры ведь не обязательно определять сразу, можно сначала объявить.

Можно подумать мало такого. При таком объявлении можно юзать только указатель на них, без обращения к неизвестным полям, что позволяет написать интерфейс к библиотеке, спрятав внутренности. Например - glib.

vodz ★★★★★
()
Ответ на: комментарий от i-rinat

Perl ужасен. Хотя для мелкой скриптни — да, он один из лучших.

Miguel ★★★★★
()
Ответ на: комментарий от anonymous

Чтобы не приходилось искать, не надо больше 500 строчек в один файл!

anonymous
()
Ответ на: комментарий от FeyFre

Лучше всего вообще main() в отдельный файл main.c запихать. Если, конечно, у тебя в исходниках больше десятка функций помимо main.

anonymous
()
Ответ на: комментарий от andreyu

Это не совсем корректный пример, так как как правило методы, определённые внутри класса будут заинлайены в отличие от методов, определённых вне класса. Плюс читать большой класс со всем внутри (особенно с несколькими вложенными определениями) становится тоскливо. Код же с прототипами/без читается более-менее одинаково (без прототипов часто лучше).

slapin ★★★★★
()
Ответ на: комментарий от i-rinat

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

slapin ★★★★★
()
Ответ на: комментарий от aureliano15

Переменные легко выпилить включением нужных ворнингов. Хуже с типами и прототипами.

slapin ★★★★★
()
Ответ на: комментарий от slapin

Это не совсем корректный пример, так как как правило методы, определённые внутри класса будут заинлайены в отличие от методов, определённых вне класса.

В приведенных мною примерах, компилятор поступит одинаково - скорее всего заинлайнит. Если бы я сделал определение в cpp, то компилятор скорее всего не сделал бы инлайн.

Плюс читать большой класс со всем внутри (особенно с несколькими вложенными определениями) становится тоскливо.

Вот поэтому определение делают или в cpp, или сразу после класса (в том же файле или во включаемом внешнем).

andreyu ★★★★★
()
Ответ на: комментарий от i-rinat

Неоднократно замечал, что некоторые люди намеренно разбивают функцию на прототип+тело, даже если можно просто функцию в одном месте определить. Зачем вы это делаете?

Тоже не понимаю этого. Хотя, в каждом проекте стиль кода свой, и тут кто как привык.

Gargamel
()
Ответ на: комментарий от hotpil

Кроме того, вся идеология разбиения кода на .c и .h файлы не работает, естественно, без отдельных прототипов.

А если функции в одном файле с main находятся? Тогда без отдельных прототипов обойтись можно.

Gargamel
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.