|
Программирование >> Перегруженные имена функций и идентификаторы
Switzerland Есть ли у кого-нибудь утилиты для перевода С-программ, написанных в старом стиле, в ANSI C и наоборот? Существуют ли программы для автоматического создания прототипов? Две программы, protoize и unprotoize осуществляют преобразование в обе стороны между функциями, записанными в новом стиле с прототипами, и функциями, записанными в старом стиле. (Эти программы не поддерживают полный перевод между классическим и ANSI C). Упомянутые программы б1ли сначала вставками в FSF GNU компилятор С, gcc, но теперь они - часть дистрибутива gcc. Программа unproto - это фильтр, располагающийся между препроцессором и следующим проходом компилятора - на лету переводит большинство особенностей ANSI C в традиционный GNU пакет GhostScript содержит маленькую программу ansi2knr. Есть несколько генераторов прототипов, многие из них - модификации программы lint. Версия 3 программы CPROTO б1ла помещена в конференцию comp.sources.misc в марте 1992 г. Есть другая программа, которая называется ctxtract . В заключение хочется спросить: так ли уж нужно преобразовывать огромное количество старых программ в ANSI C? Старый стиль написания функций все еще допустим. Я пытаюсь использовать ANSI-строкообразующий оператор #, чтобы вставить в сообщение значение символической константы, но вставляется формальный параметр макроса, а не его значение Необходимо использовать двухшаговую процедуру дя того чтобы макрос раскрывался как при строкообразовании: #define str(x) #x #define xstr(x) str(x) #define OP plus char *opname = xstr(OP); Такая процедура устанавливает opname равным plus , а не OP . Такие же обходные маневры необходимы при использовании оператора склеивания лексем ##, когда нужно соединить значения (а не имена формальных параметров) двух макросов. Не понимаю, почему нельзя использовать неизменяемые значения при инициализации переменных и задании размеров массивов, как в следующем примере: const int n = 5; int a[n]; Квалификатор const означает только для чтения . Любой объект, квалифицированный как const, представляет собой нормальный объект, существующий во время исполнения программы, которому нельзя присвоить другое значение. Следовательно, значение такого объекта - это не константное выражение в полном смысле этого слова. (В этом смысле Си не похож на С++). Если есть необходимость в истинных константах, работающих во время компиляции, используйте препроцессорную директиву #define. Какая разница между char const *p и char * const p ? char const *p - это указатель на постоянную литеру (ее нельзя изменить); char * const p - это неизменяемый указатель на переменную (ее можно менять ) типа char. Зарубите это себе на носу. Почему нельзя передать char ** функции, ожидающей const char **? Можно использовать указатель-на-Т любых типов Т, когда ожидается укaзaтель-нa-const-Т, но правило (точно определенное исключение из него), разрешающее незначительные отличия в указателях, не может применяться рекурсивно, а только на самом верхнем уровне. Необходимо использовать точное приведение типов (т.е. в данном случае (const char **)) при присвоении или передаче указателей, которые имеют различия на уровне косвенной адресации, отличном от первого. Мой ANSI компилятор отмечает несовпадение, когда встречается с декларациями: extern int func(float); int func(x) float x; {... Вы смешали декларацию в новом стиле extern int func(float); с определением функции в старом стие int func(x) float x; . Смешение стилей, как правило, безопасно, но только не в этом случае. Старый Си (и ANSI С при отсутствии прототипов и в списках аргументов переменной длины) расширяет аргументы определенных типов при передаче их функциям. Аргументы типа float преобразуются в тип double, литеры и короткие целые преобразуются в тип int. (Если функция определена в старом стиле, параметры автоматически преобразуются в теле функции к менее емким, если таково их описание там.) Это затруднение может быть преодолено либо с помощью определений в новом стиле: int func(float x) { ... } либо с помощью изменения прототипа в новом стиле таким образом, чтобы он соответствовал определению в старом стиле: extern int func(double); (В этом случае для большей ясности было бы желательно изменить и определение в старом стиле так, чтобы параметр, если только не используется его адрес, был типа double.) Возможно, будет безопасней избегать типов char, short int, float для возвращаемых значений и аргументов функций. Можно ли смешивать определения функций в старом и новом стиле? Смешение стилей абсолютно законно, если соблюдается осторожность. Заметьте, однако, что определение функций в старом стиле считается выходящим из употребления, и в один прекрасный момент поддержка старого стиля может быть прекращена. Почему объявление extern f(struct x {int s;} *p); порождает невнятное предупреждение struct x introduced in prototype scope (структура объявлена в зоне видимости прототипа)? В странном противоречии с обычными правилами для областей видимости структура, объявленная только в прототипе, не может быть совместима с другими структурами, объявленными в этом же файле. Более того, вопреки ожиданиям тег структуры не может быть использован после такого объявления (зона видимости объявления простирается до конца прототипа). Для решения проблемы необходимо, чтобы прототипу предшествовало пустое объявление: struct x; которое зарезервирует место в области видимости файла для определения структуры x. Определение будет завершено объявлением структуры внутри прототипа.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |