Аргументы
Аргументы в вызове функции могут иметь следующую форму:
expression ( expression-listopt ) /* Вызов функции */
При вызове функции параметр expression-list содержит список выражений, разделенных запятыми. Значения этих выражений являются аргументами, которые передаются функции. Если функция не принимает аргументы, то список expression-list должен содержать ключевое слово void
.
Аргументом может быть любое значение фундаментального типа или типа структуры, объединения или указателя. Все аргументы передаются по значению. Это означает, что параметру присваивается копия соответствующего аргумента, а где именно переданный аргумент находится в памяти, функции неизвестно. Она лишь обрабатывает полученную копию, не затрагивая исходную переменную.
Хотя массивы и функции не могут передаваться в качестве аргументов, вы можете передать указатели на них. Благодаря этому функция сможет обращаться к значению по ссылке. Поскольку указатель на переменную содержит адрес переменной, то функция может обращаться к значению по этому адресу. Аргументы-указатели позволяют функции обращаться к массивам и функциям, хотя сами они и не могут передаваться в качестве аргументов.
Порядок вычисления аргументов может различаться в зависимости от конкретного компилятора и уровня оптимизации. Однако аргументы и все побочные эффекты полностью вычисляются до входа в функцию. Дополнительные сведения см. в статье Побочные эффекты.
При вызове функции вычисляются все выражения из списка expression-list, и для каждого аргумента выполняются обычные арифметические преобразования. Если доступен прототип, то результат вычисления аргументов сравнивается по типу с соответствующим параметром прототипа. Если они не совпадают, то либо выполняется преобразование, либо выводится диагностическое сообщение. Для параметров также проводятся обычные арифметические преобразования.
Количество выражений в expression-list должно совпадать с количеством параметров, если в прототипе или определении функции не указано явным образом переменное количество аргументов. В этом случае компилятор проверяет столько аргументов, сколько имен типов содержится в списке параметров. При необходимости он преобразует их, как описано выше. Дополнительные сведения см. в статье Вызовы с переменным количеством аргументов.
Если список параметров прототипа содержит только ключевое слово void
, то компилятор не ожидает ни аргументов в вызове функции, ни параметров в определении. Если аргументы будут обнаружены, он выведет диагностическое сообщение.
Пример
В следующем примере в качестве аргументов используются указатели:
int main()
{
/* Function prototype */
void swap( int *num1, int *num2 );
int x, y;
.
.
.
swap( &x, &y ); /* Function call */
}
/* Function definition */
void swap( int *num1, int *num2 )
{
int t;
t = *num1;
*num1 = *num2;
*num2 = t;
}
В этом примере функция swap
объявлена внутри функции main
. Она имеет два аргумента, num1
и num2
, которые являются указателями на значения типа int
. Параметры num1
и num2
в определении прототипа также объявляются как указатели на значения типа int
.
Функция вызывается следующей инструкцией:
swap( &x, &y )
Адрес x
, который здесь используется, сохраняется в аргументе num1
, а адрес y
— в аргументе num2
. Теперь для одного и того же местоположения имеется два имени, или псевдонима. Ссылки на значения *num1
и *num2
в функции swap
одновременно представляют собой ссылки на значения x
и y
в функции main
. Присваивания внутри функции swap
, по сути, меняют содержимое переменных x
и y
. Поэтому оператор return
не требуется.
Компилятор выполняет проверку типов для аргументов функции swap
, поскольку в прототипе swap
указаны типы аргументов для каждого параметра. Идентификаторы, приведенные в круглых скобках в прототипе и определении функции, могут совпадать, но могут и различаться. Важно лишь то, что типы аргументов в функции должны соответствовать типам параметров как в прототипе, так и в определении.