Как правильно создавать функции?

100
27 февраля 2022, 19:50

Работая со старым кодом, столкнулся с интересным стилем.

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

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

Answer 1

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

Попытаюсь объяснить простыми словами.

Во-первых, вам нужно понять разницу между объявлением и определением:

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

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

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

И здесь уже стоит сказать о том, что компилятор может скомпилировать код, использующий некторую функцию, даже не зная определения самой этой функции. Это приводит к широчайшим возможностям (раздельная компиляция, динамически подключаемые библиотек и так далее).

Например, вы наверняка сталкивались с использованием функции printf из стандартной библиотеки:

#include <stdio.h>
int main(void)
{
    printf("Hello, World!\n");
}

Это программа компилируется и отлично работает. Но ведь у нас нет ни объявления, ни определения функции printf! Как компилятор вообще смог все это скомпилировать?

На самом деле, объявление функции у нас есть, и содержится оно в заголовочном файле <stdio.h>1 и выглядит (один из возможных вариантов) так:

extern int printf (const char *__restrict __format, ...);

Это объявление, которое называют прототипом (англ. function prototype), говорит компилятору, как нужно вызывать эту функцию. И компилятор успешно генерирует ассемблерный код для ее вызова.

Объявление же этой функции становится известно только во время запуска программы, во время динамической линковки библиотеки, содержащей это определение. В роли библиотеки в данном случае выступает стандартная библиотека языка C, вернее ее конкрентая реализация (GNU C Library, в моем случае).

1. В теории, мы можем вообще не подключать <stdio.h>, а скопировать протип функции printf прямо в наш код. Хотя делать так, конечно, не стоит.

READ ALSO
перевод каждого элемента стринг в инт

перевод каждого элемента стринг в инт

что нужно написать в цикле чтобы перевести каждый элемент стринга в инт и прибавить его в 'c'

86
Удаление пробелов из строки

Удаление пробелов из строки

Как удалить все пробелы из строки

82
Вывести совпадения Laravel + MySql

Вывести совпадения Laravel + MySql

Как вывести совпадения для пользователя -user_i = 1Нужно вывести пользователей, которых лайкнул пользователь 1 и те пользователя, которые лайкнули...

89