Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЗФ_ОАиП / Лекции ГГУ Скорины - Программирование.doc
Скачиваний:
179
Добавлен:
21.03.2016
Размер:
2.27 Mб
Скачать

24.2. Объявление списка параметров переменной длины

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

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

Например, следующий прототип указывает, что у функции func() будет как минимум два целых параметра и после них еще некоторое количество (в том числе и ноль) параметров:

int func(int a, int b, ...);

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

int func(...); // ошибка

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

int func(int a, ..., int b); // ошибка

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

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

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

Задача. Написать функцию для нахождения суммы произвольного числа неотрицательных длинных целых чисел (long).

long sum1(int n, long p, ...) { // n – количество параметров

long s = 0, *pa;

int i;

pa = &p; // получаем адрес первого параметра

for (i = 0; i < n; i++) {

s += *pa;

pa++; // переходим к следующему параметру

}

return s;

}

long sum2(long p, ...) { // признак конца: число < 0

long s = 0, *pa;

pa = &p; // получаем адрес первого параметра

while (*pa >= 0) {

s += *pa;

pa++; // переходим к следующему параметру

}

return s;

}

void main() {

long s, p1 = 1, p2 = 2, p3 = 3, p4 = 4, p5 = 5;

s = sum1(5, 1L, 2L, 3L, 4L, 5L);

s = sum1(5, p1, p2, p3, p4, p5);

s = sum2(1L, 2L, 3L, 4L, 5L, -1L);

// ошибка, т. к. параметры должны занимать в стек по 4 байта (long),

// а не по 2 (int)

// s = sum1(5, 1, 2, 3, 4, 5); // ошибка!!!

}

Для доступа к фактическим параметрам в стеке используется увеличение указателя, что соответствует соглашению о вызовах cdecl – последний параметра помещается в стек первым, затем – второй и т.д. Значит первый параметр будет иметь меньший адрес, чем второй и т.д.

Для вызова функции sum2() из примера в стеке будем иметь:

← вершина стека

1

параметр 1

2

параметр 2

3

параметр 3

4

параметр 4

5

параметр 5