Незаданное Число Параметров

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

int printf(char* ...);

Это задает, что в вызове printf должен быть само мало один параметр, char*, а другие Незаданное Число Параметров могут быть, а могут и не быть. К примеру:

printf("Hello, world\n");

printf("Мое имя %s %s\n", first_name, second_name);

printf("%d + %d = %d\n",2,3,5);

Такая функция полагается на информацию, которая недосягаема компилятору при интерпретации ее перечня характеристик. В случае printf() первым параметром является строчка Незаданное Число Параметров формата, содержащая особые последовательности знаков, дозволяющие printf() верно обрабатывать другие характеристики. %s значит "ожидай параметра char*", а %d значит "ожидай параметра int". Но, компилятор этого не знает, потому он не может убедиться в том, что ожидаемые характеристики имеют соответственный тип. К примеру:

printf("Мое имя %s %s\n Незаданное Число Параметров",2);

откомпилируется и в наилучшем случае приведет к какой-либо необычного вида выдаче.

Разумеется, если параметр не был описан, то у компилятора нет инфы, нужной для выполнения над ним проверки типа и преобразования типа. В данном случае char либо short передаются как int, а float передается как double. Это не Незаданное Число Параметров непременно то, чего ожидает юзер.

Чрезмерное внедрение многоточий, вроде wild(...), стопроцентно выключает проверку типов характеристик, оставляя программера открытым перед обилием проблем, которые отлично знакомы программерам на C. В отлично обмысленной программке требуется самое большее несколько функций, для которых типы характеристик не определены стопроцентно. Для того, чтоб позаботиться о Незаданное Число Параметров проверке типов, можно использовать перегруженные функции и функции с параметрами по дефлоту в большинстве тех случаев, когда по другому пришлось бы бросить типы характеристик незаданными. Многоточие нужно только если меняются и число характеристик, и тип характеристик. Более обыденное применение многоточия в задании интерфейса с функциями C библиотек, которые были определены Незаданное Число Параметров в то время, когда кандидатуры не было:

extern int fprintf(FILE*, char* ...); // из

extern int execl(char* ...); // из

extern int abort(...); // из

Разберем случай написания функции ошибок, которая получает один целый параметр, указывающий серьезность ошибки, после которого идет случайное число строк. Мысль заключается в том, чтоб составлять сообщение об ошибке при помощи передачи Незаданное Число Параметров каждого слова как отдельного строкового параметра:

void error(int ...);

main(int argc, char* argv[])

{

switch(argc) {

case 1:

error(0,argv[0],0);

break;

case 2:

error(0,argv[0],argv[1],0);

default:

error(1,argv[0],"с",dec(argc-1),"параметрами",0);

}

}

Функцию ошибок можно найти так:

#include

void error(int n ...)

/*

"n" с следующим перечнем char*, оканчивающихся нулем

*/

{

va_list ap Незаданное Число Параметров;

va_start(ap,n); // раскрутка arg

for (;;) {

char* p = va_arg(ap,char*);

if(p == 0) break;

cerr << p << " ";

}

va_end(ap); // чистка arg

cerr << "\n";

if (n) exit(n);

}

1-ый из va_list определяется и инициализируется вызовом va_start(). Макрос va_start получает имя va_list'а и имя последнего формального параметра Незаданное Число Параметров как характеристики. Макрос va_arg употребляется для выбора неименованных характеристик по порядку. При каждом воззвании программер должен задать тип; va_arg() подразумевает, что был передан фактический параметр, но обычно метода убедиться в этом нет. Перед возвратом из функции, в какой был применен va_start(), должен быть вызван Незаданное Число Параметров va_end(). Причина в том, что va_start() может поменять стек так, что нельзя будет удачно выполнить возврат; va_end() аннулирует все эти конфигурации.

Указатель на Функцию

С функцией можно делать только две вещи: вызывать ее и брать ее адресок. Указатель, приобретенный взятием адреса функции, можно потом использовать для Незаданное Число Параметров вызова этой функции. К примеру:

void error(char* p) { /* ... */ }

void (*efct)(char*); // указатель на функцию

void f()

{

efct = &error; // efct показывает на error

(*efct)("error"); // вызов error через efct

}

Чтоб вызвать функцию через указатель, к примеру, efct, нужно поначалу этот указатель разыменовать, *efct. Так как операция вызова функции () имеет более высочайший ценность Незаданное Число Параметров, чем операция разыменования *, то нельзя писать просто *efct("error"). Это значит *efct("error"), а это ошибка в типе. То же относится и к синтаксису описаний (см. также #7.3.4).

Заметьте, что у указателей на функции типы характеристик описываются точно также, как и в самих функциях. В присваиваниях указателя должно соблюдаться четкое соответствие полного типа Незаданное Число Параметров функции. К примеру:

void (*pf)(char*); // указатель на void(char*)

void f1(char*); // void(char*)

int f2(char*); // int(char*)

void f3(int*); // void(int*)

void f()

{

pf = &f1; // ok

pf = &f2; // ошибка: не подходит возвращаемый тип

pf = &f3; // ошибка: не подходит тип параметра

(*pf)("asdf"); // ok

(*pf)(1); // ошибка: не подходит тип Незаданное Число Параметров параметра

int i = (*pf)("qwer"); // ошибка: void присваивается int'у

}

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

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

typedef int (*SIG_TYP Незаданное Число Параметров)(); // из

typedef void (*SIG_ARG_TYP);

SIG_TYP signal(int,SIG_ARG_TYP);

Бывает нередко полезен вектор указателей на функцию. К примеру, система меню для моего редактора с мышью*4 реализована при помощи векторов указателей на функции для представления действий. Тщательно эту систему тут обрисовать не получится, но вот общая мысль:

typedef Незаданное Число Параметров void (*PF)();

PF edit_ops[] = { // операции редактирования

cut, paste, snarf, search

};

PF file_ops[] = { // управление файлом

open, reshape, close, write

};

Потом определяем и инициализируем указатели, определяющие деяния, избранные в меню, которое связано с клавишами (button) мыши:

PF* button2 = edit_ops;

PF* button3 = file_ops;

В полной реализации для определения каждого пт меню требуется больше инфы Незаданное Число Параметров. К примеру, кое-где должна храниться строчка, задающая текст, который высвечивается. При использовании системы значение кнопок мыши нередко изменяется зависимо от ситуации. Эти конфигурации осуществляются (отчасти) средством смены значений указателей кнопок. Когда юзер выбирает пункт меню, к примеру пункт 3 для кнопки 2, производится связанное с ним действие:

(button Незаданное Число Параметров2[3])();

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

Указатели на функции можно использовать для задания полиморфных подпрограмм, другими словами Незаданное Число Параметров подпрограмм, которые могут применяться к объектам многих разных типов:

typedef int (*CFT)(char*,char*);

int sort(char* base, unsigned n, int sz, CFT cmp)

/*

Сортирует "n" частей вектора "base"

в вырастающем порядке

при помощи функции сопоставления, указываемой "cmp".

Размер частей "sz".

Очень неэффективный метод: пузырьковая сортировка

*/

{

for (int i Незаданное Число Параметров=0; iname, Puser(q)->name);

}

int cmp2(char*p, char* q) // Ассоциирует числа dept

{

return Puser(p)->dept-Puser(q)->dept;

}

Эта программка сортирует и печатает:

main ()

{

sort((char*)heads,6,sizeof(user),cmp1);

print_id(heads,6); // в алфавитном порядке

cout << "\n";

sort((char*)heads,6,sizeof(user),cmp2);

print_id(heads,6); // по порядку подразделений

}

Можно взять Незаданное Число Параметров адресок inline-функции, как, вобщем, и адресок перегруженной функции(#с.8.9).

Макросы

Макросы *5 определяются в #с.11. В C они очень важны, но в C++ используются еще меньше. 1-ое правило относительно их такое: не используйте их, если вы не должны это делать. Как было увидено, практически каждый макрос проявляет собственный Незаданное Число Параметров недостаток либо в языке, либо в программке. Если вы желаете использовать макросы, прочитайте, пожалуйста, сначала очень пристально управление по вашей реализации C препроцессора.
Обычный макрос определяется так:

#define name rest of line

Когда name встречается как лексема, оно заменяется на rest of line. К примеру:

named = name

после расширения даст:

named Незаданное Число Параметров = rest of line

Можно также найти макрос с параметрами. К примеру:

#define mac(a,b) argument1: a argument2: b

При использовании mac должно даваться две строчки параметра. После расширения mac() они подменяют a и b. К примеру:

expanded = mac(foo bar, yuk yuk)

после расширения даст

expanded = argument1: foo bar argument2: yuk yuk

Макросы обрабатывают Незаданное Число Параметров строчки и о синтаксисе C++ знают сильно мало, а о типах C++ либо областях видимости - ничего. Компилятор лицезреет только расширенную форму макроса, потому ошибка в макросе диагностируется когда макрос расширен, а не когда он определен. В итоге этого появляются непонятные сообщения об ошибках.

Вот такими макросы могут быть Незаданное Число Параметров полностью:

#define Case break;case

#define nl <<"\n"

#define forever for(;;)

#define MIN(a,b) (((a)

Вот совсем ненадобные макросы:

#define PI 3.141593

#define BEGIN {

#define END }

А вот примеры небезопасных макросов:

#define SQUARE(a) a*a

#define INCR_xx (xx)++

#define DISP = 4

Чтоб узреть, чем они небезопасны, попытайтесь провести расширения в Незаданное Число Параметров последующем примере:

int xx = 0; // глобальный счетчик

void f() {

int xx = 0; // локальная переменная

xx = SQUARE(xx+2); // xx = xx+2*xx+2

INCR_xx; // наращивает локальный xx

if (a-DISP==b) { // a-= 4==b

// ...

}

}

Если вы обязаны использовать макрос, при ссылке на глобальные имена используйте операцию разрешения области видимости :: (#2.1.1) и заключайте вхождения имени параметра макроса в скобки всюду, где Незаданное Число Параметров это может быть (см. MIN выше).

Направьте внимание на различие результатов расширения этих 2-ух макросов:

#define m1(a) something(a) // широкомысленный комментарий

#define m2(a) something(a) /* широкомысленный комментарий */

к примеру,

int a = m1(1)+2;

int b = m2(1)+2;

асширяется в

int a = something(1) // широкомысленный комментарий+2;

int b = something(1) /* широкомысленный комментарий */+2;

При Незаданное Число Параметров помощи макросов вы сможете создать собственный свой язык. Вероятнее всего, для всех других он будет непостижим. Не считая того, C препроцессор - очень обычный макропроцессор. Когда вы попытаетесь сделать что-либо нетривиальное, вы, возможно, обнаружите, что сделать это или нереально, или очень тяжело (но см. #7.3.5).

Упражнения

(*1) Напишите последующие описания: функция, получающая параметр типа Незаданное Число Параметров указатель на знак и ссылку на целое и не возвращающая значения; указатель на такую функцию; функция, получающая таковой указатель в качестве параметра; и функция, возвращающая таковой указатель. Напишите определение функции, которая получает таковой указатель как параметр и возвращает собственный параметр как возвращаемое значение. Подсказка: используйте typedef.

(*1) Что это означает Незаданное Число Параметров? Зачем это может употребляться?

typedef int (rifii&) (int, int);

(*1.5) Напишите программку вроде "Hello, world", которая получает имя как параметр командной строчки и печатает "Hello, имя". Видоизмените эту программку так, чтоб она получала получала хоть какое количество имен и гласила hello каждому из их.

(*1.5) Напишите программку, которая читает случайное число Незаданное Число Параметров файлов, имена которых задаются как аргументы командной стоки, и пишет их один за одним в cout. Так как эта программка при выдаче конкатенирует свои характеристики, вы сможете именовать ее cat (кошка).

(*2) Преобразуйте маленькую C программку в C++. Измените заголовочные файлы так, чтоб обрисовывать все вызываемые функции и обрисовывать тип Незаданное Число Параметров каждого параметра. Поменяйте, где может быть, директивы #define на enum и const либо inline. Уберите из .c файлов описания extern и преобразуйте определения функций к синтаксису C++. Поменяйте вызовы malloc() и free() на new и delete. Уберите необязательные приведения типа.

(*2) Реализуйте sort() (#4.6.7) используя действенный метод сортировки Незаданное Число Параметров.

(*2) Поглядите на определение struct tnode в с.#8.5. Напишите функцию для введения новых слов в дерево узлов tnode. Напишите функцию для вывода дерева узлов tnode. Напишите функцию для вывода дерева узлов tnode со словами в алфавитном порядке. Видоизмените tnode так, чтоб в нем хранился (только) указатель на слово случайной длины, помещенное при помощи Незаданное Число Параметров new в свободную память. Видоизмените функции для использования нового определения tnode.

(*2) Напишите "модуль", реализующий стек. Файл .h должен обрисовывать функции push(), pop() и любые другие комфортные функции (только). Файл .c определяет функции и данные, нужные для хранения стека.

(*2) Узнайте, какие у вас есть стандартные заголовочные файлы. Составьте перечень файлов Незаданное Число Параметров, находящихся в /usr/include и /usr/include/CC (либо там, где хранятся стандартные заголовочные файлы в вашей системе). Прочитайте все, что покажется увлекательным.

(*2) Напишите функцию для воззвания двумерного массива.

(*2) Напишите шифрующую программку, которая читает из cin и пишет в cout закодированные знаки. Вы сможете пользоваться последующей обычной схемой шифровки Незаданное Число Параметров: Зашифрованная форма знака c - это c^key[i], где key (ключ) - строчка, которая передается как параметр командной строчки. Программка употребляет знаки из key циклически, пока не будет считан весь ввод. Перекодирование зашифрованного текста с той же строчкой key дает начальный текст. Если не передается никакого ключа (либо передается Незаданное Число Параметров пустая строчка), то никакого кодировки не делается.

(*3) Напишите программку, которая поможет расшифровывать тексты, зашифрованные описанным выше методом, не зная ключа. Подсказка: David Kahn: The Code-Breakers, Macmillan, 1967, New York, pp 207-213.

(*3) Напишите функцию error, которая получает форматную строчку в стиле printf, которая содержит директивы %s, %c и %d, и случайное количество Незаданное Число Параметров характеристик. Не используйте printf(). Если вы не понимаете значения %s и т.д., поглядите #8.2.4. Используйте .

(*1) Как вы будете выбирать имя для указателя на тип функции, определенный при помощи typedef?

(*2) Поглядите какие-нибудь программки, чтоб сделать представление о многообразии стилей и имен, использующихся на практике. Как употребляются буковкы в Незаданное Число Параметров верхнем регистре? Как употребляется подчерк? Где употребляются недлинные имена вроде x и y?

(*1) Что некорректно в последующих макроопределениях?

#define PI = 3.141593

#define MAX(a,b) a>b?a:b

#define fac(a) (a)*fac((a)-1)

(*3) Напишите макропроцессор, который определяет и расширяет обыкновенные макросы (как C препроцессор). Читайте из cin и пишите Незаданное Число Параметров в cout. Поначалу не пытайтесь обрабатывать макросы с параметрами. Подсказка: В настольном калькуляторе (#3.1) есть таблица имен и лексический анализатор, которые вы сможете видоизменять.

*1 либо линкер. (прим. перев.)

* 2C разработан так, чтоб почти всегда позволять производить неявную сборку. Применение C, но, возросло несусветно, потому случаи, когда можно использовать неявную линковку Незаданное Число Параметров, на данный момент составляют малозначительное меньшинство. (прим. создателя)

*3 Просто поменять один компоновщик, но сделав это и написав программку, которая находится в зависимости от усовершенствований, как вы будете переносить эту программку в другое место? (прим. создателя)
*4 Мышь - это указывающее устройство по последней мере с одной кнопкой. Моя мышь Незаданное Число Параметров красноватая, круглая и с 3-мя клавишами. (прим. создателя)
*5 нередко именуемые также макроопределениями. (прим. перев.)


nicshe-fridrih-vilgelm.html
niczettaavtorshepelevp-skemerovo2012httpkemerovo3000-ru-stranica-10.html
niczettaavtorshepelevp-skemerovo2012httpkemerovo3000-ru-stranica-15.html