Ситуация, когда "путь" вычислений приводит в конец функции (т. е. на последнюю закрывающую фигурную скобку), равносильна выполнению return - инструкции без выражения. При этом, а также в случае явного задания return без выражения возвращаемое значение не определено
То, что подготовлено в качестве ввода для Си-компилятора, называется единицей трансляции. Она состоит из последовательности внешних объявлений, каждое из которых представляет собой либо объявление, либо определение функции.
единица-трансляции :
внешнее-объявление
единица-трансляции внешнее-объявление
внешнее-объявление :
определение-функции
объявление
Область видимости внешних объявлений простирается до конца единицы трансляции, в которой они объявлены, точно так же, как область видимости объявлений в блоке распространяется до конца этого блока. Синтаксис внешнего объявления не отличается от синтаксиса любого другого объявления за одним исключением: код функции можно определять только с помощью внешнего объявления.
A10.1. Определение функции
Определение функции имеет следующий вид:
определение-функции :
спецификаторы-объявления необобъявитель список-объявлений необ
составная-инструкция
Из спецификаторов класса памяти в спецификаторах-объявлениях возможны только extern и static ; различия между последними рассматриваются в A11.2.
Типом возвращаемого функцией значения может быть арифметический тип, структура, объединение, указатель и void , но не "функция" и не "массив". Объявитель в объявлении функции должен явно указывать на то, что описываемый им идентификатор имеет тип "функция", т. е. он должен иметь одну из следующих двух форм (A8.6.3):
собственно-объявитель ( список-типов-параметров )
собственно-объявитель ( список-идентификаторов необ )
где собственно-объявитель есть идентификатор или идентификатор, заключенный в скобки. Заметим, что тип "функция" посредством typedef получить нельзя.
Первая форма соответствует определению функции новым способом, для которого характерно объявление параметров в списке-типов-параметров вместе с их типами; за объявителем не должно быть списка-объявлений. Если список-типов-параметров не состоит из одного-единственного слова void , показывающего, что параметров у функции нет, то в каждом объявителе в списке-типов-параметров обязан присутствовать идентификатор. Если список-типов-параметров заканчивается знаками ", ...", то вызов функции может иметь аргументов больше, чем параметров; в таком случае, чтобы обращаться к дополнительным аргументам, следует пользоваться механизмом макроса va_arg из заголовочного файла , описанного в приложении B. Функции с переменным числом аргументов должны иметь по крайней мере один именованный параметр.
Вторая форма - определение функции старым способом. Список-идентификаторов содержит имена параметров, а список-объявлений приписывает им типы. В списке- объявлении разрешено объявлять только именованные параметры, инициализация запрещается, и из спецификаторов класса памяти возможен только register .
И в том и другом способе определения функции мыслится, что все параметры как бы объявлены в самом начале составной инструкции, образующей тело функции, и совпадающие с ними имена здесь объявляться не должны (хотя, как и любые идентификаторы, их можно переобъявить в более внутренних блоках). Объявление параметра "массив из типа " можно трактовать как "указатель на тип ", аналогично объявлению параметра объявление "функция, возвращающая тип " можно трактовать как "указатель на функцию, возвращающую тип ". В момент вызова функции ее аргументы соответствующим образом преобразуются и присваиваются параметрам (см. A7.3.2).
Новый способ определения функций введен ANSI-стандартом. Есть также небольшие изменения в операции повышения типа; в первой версии языка параметры типа float следовало читать как double . Различие между float и double становилось заметным, лишь когда внутри функции генерировался указатель на параметр.
Ниже приведен пример определения функции новым способом:
int max(int a, int b, int c)
{
int m;
m = (a > b) ? a: b;
Читать дальше