|
Программирование >> Перегруженные имена функций и идентификаторы
Мне попалась программа, в которой, на мой взгляд, слишком много директив препроцессора #ifdef. Как обработать текст, чтобы оставить только один вариант условной компиляции, без использования cpp, а также без раскрытия всех директив #include и #define? Свободно распространяются программы unifdef, rmifdef и scpp, которые делают в точности то, что вам нужно. Как получить список предопределенных идентификаторов? Стандартного способа не существует, хотя необходимость возникает часто. Если руководство по компилятору не содержит этих сведений, то, возможно, самый разумный путь - выделить текстовые строки из исполнимых файлов компилятора или препроцессора с помощью утилиты типа strings(l) системы Unix. Имейте в виду, что многие зависящие от системы предопределенные идентификаторы (например, unix ) нестандартны (поскольку конфликтуют с именами пользователя) и поэтому такие идентификаторы удаляются или меняются. Как написать cpp макрос с переменным количеством аргументов? Популярна такая уловка: определить макрос с одним аргументом, и вызывать его с двумя открывающими и двумя закрывающими круглыми скобками: #define DEBUG(args) (printf( DEBUG: ), printf args) if(n != 0) DEBUG(( n is /od\n , n)); Очевидный недостаток такого подхода в том, что нужно помнить о дополнительных круглых скобках. Другие решения - использовать различные макросы (DEBUG1, DEBUG2, и т.п.) в зависимости от количества аргументов, или манипулировать запятыми: #define DEBUG(args) (printf( DEBUG: ), printf(args)) #define , DEBUG( i = %d i) Часто предпочтительнее использовать настоящую функцию, которая стандартным способом может использовать переменное число аргументов. Как реализовать функцию с переменным числом аргументов? Используйте головной файл <stdarg.h> (или, если необходимо, более старый <varargs.h>). Вот пример функции, которая объединяет произвольное количество стрингов, помещая результат в выделенный с помощью malloc участок памяти. #include <stdlib.h> /* для malloc, NULL, size t */ #include <stdarg.h> /* для va макросов */ #include <string.h> /* для strcat и т.п. */ char *vstrcat(char *first, ... ) size t len = 0; char *retbuf; va list argp; char *p; if(first == NULL) return NULL; len = strlen(first); va start(argp, first); while((p = va arg(argp, char *)) != NULL) len += strlen(p); va end(argp); retbuf = malloc(len + 1); /* +1 для \0 */ if(retbuf == NULL) return NULL; /* ошибка */ (void)strcpy(retbuf, first); va start(argp, first); while((p = va arg(argp, char *)) != NULL) (void)strcat(retbuf, p); va end(argp); return retbuf; Вызывается функция примерно так: char *str = vstrcat( Hello, , world! , (char *)NULL); Обратите внимание на явное приведение типа в последнем аргументе. (Помните также, что после вызова такой функции нужно освободить память). Если компилятор разрабатывался до приема стандарта ANSI, перепишите определение функции без прототипа ( char *vstrcat(first) char *first; { ) включите <stdio.h> вместо <stdlib.h>, добавьте extern char *malloc(); , и используйте int вместо size t. Возможно, придется удалить приведение (void) и использовать varargs.h вместо stdarg. Помните, что в прототипах функций со списком аргументов переменной длины не указывается тип аргументов. Это значит, что по умолчанию будет происходить расширение типов аргументов. Это также значит, что тип нулевого указателя должен быть явно указан. Как написать функцию, которая бы, подобно printf, получала строку формата и переменное число аргументов, а затем для выполнения большей части работы передавала бы все это printf? Используйте vprintf, vfprintf или vsprintf. Перед вами подпрограмма error , которая после строки error: печатает сообщение об ошибке и символ новой строки. #include <stdio.h> #include <stdarg.h> void error(char *fmt, ... ) va list argp; fprintf(stderr, error: ); va start(argp, fmt); vfprintf(stderr, fmt, argp); va end(argp); fprintf(stderr, \n ); Чтобы использовать старый головной фай <varargs.h> вместо <stdarg.h>, измените заголовок функции: void error(va alist) va dcl char *fmt; измените строку с va start: va start(argp); и добавьте строку fmt = va arg(argp, char *); между вызовами va start и vfprintf. Заметьте, что после va dcl нет точки с запятой.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |