Стив Саммит. Язык си в вопросах и ответах.Разное (Пребразование Fortran -> C , грамматики для YACC и т.п.)

Стив  Саммит. Язык си в вопросах и ответах.Стив  Саммит. Язык си в вопросах и ответах.Разное (Пребразование Fortran -> C , грамматики для    YACC и т.п.)

Ответы на вопросы разбиты по темам:

1. Нулевые указатели

2. Указатели и массивы.

3. Выделение памяти

4. Выражения

5. ANSI C

6. Препроцессор С.

7. Списки аргументов переменной длины.

8. Булевы выражения и переменные.

9. Структуры, перечисления и объединения.

10. Декларации.

11. Cтандартный ввод/вывод.

12. Библиотечные функции.

13. Lint.

14. Стиль.

15. Операции с плавающей точкой.

16. Интерфейс с операционной системой.

17. Разное (Пребразование Fortran -> C , грамматики для YACC и т.п.)

Разное.

17.1    Что можно с уверенностью сказать о начальных значениях переменных, которые явным образом не инициализированы? Если глобальные переменные имеют нулевое начальное значение, то правильно ли нулевое значение присваивается указателям и переменным с плавающей точкой?

А:    «Cтатические» переменные (то есть объявленные вне функций и те,    что объявлены как принадлежащие классу stаtic) всегда инициализируются (прямо при старте программы) нулем, как    будто программист написал «=0». Значит, переменные будут инициализированы    как нулевые указатели (соответствующего типа;    см. раздел 1), если они    объявлены указателями, или значениями 0.0, если были объявлены переменные с плавающей точкой.
Переменные автоматического класса (т.е.    локальные переменные без спецификации static), если они явно не определены, первоначально содержат «мусор». Никаких полезных предсказаний относительно мусора сделать нельзя.
Память,    динамически выделяемая с помощью malloc    и realloc также будет содержать    мусор и    должна быть инициализирована, если это необходимо, вызывающей программой. Память, выделенная с помощью calloc, зануляет все биты, что не всегда годится для указателей или переменных с плавающей точкой (см. вопрос 3.13 и раздел 1).

17.2    Этот текст взят    прямо из книги,    но он не компилируется.
f() { char a[] = «Hello, world!»; }
О:    Возможно, Ваш компилятор создан    до принятия стандарта ANSI и еще не поддерживает инициализацию «автоматических агрегатов» (то есть нестатических локальных массивов и структур).
Чтобы выкрутиться из этой ситуации, сделайте массив статическим    или глобальным, или инициализируйте его с помощью strcpy, когда вызывается f(). (Всегда можно инициализировать автоматическую переменную char * стрингом литер, но см. вопрос 17.20). См. также вопросы 5.16, 5.17.

17.3    Как писать данные в файл, чтобы их можно было читать на машинах с другим размером слова, порядком байтов или другим форматом чисел с плавающей точкой?

О:    Лучшее решение — использовать текстовые    файлы (обычно ASCII), c данными, записанными fprintf.    Читать данные лучше всего с помощью    fscanf или чего-то подобного. (Такой же    совет применим для сетевых протоколов). К мнениям, что    текстовые файлы    слишком велики и могут долго обрабатываться, относитесь скептически. Помимо того, что эффективность таких операций может быть на практике приемлемой, способность манипулировать данными с помощью стандартных средств    может иметь решающее значение.
Если необходимо    использовать двоичный формат, переносимость данных можно улучшить (или получить выгоду от использования готовых библиотек ввода/вывода), если использовать стандартные форматы данных, такие как XDR (RFC 1014) (Sun), ASN.1(OSI), X.409 (CCITT), или ISO 8825 «Основные правила кодирования» См. также вопрос 9.11.

17.4    Как вставить или удалить строку    (или запись) в середине    файла?

О:      Придется, видимо, переписать файл. См. вопрос 16.9.

17.5    Как возвратить из функции несколько значений?

О:    Или передайте указатель    на то место, которое будет заполнено функцией, или пусть функция возвращает структуру,    содержащую желаемые значения, или подумайте о глобальных переменных (если их немного). См. также вопросы 2.17, 3.4, и 9.2.

17.6    Если есть указатель (char *) на    имя функции в виде стринга, то как эту функцию вызвать?

О:    Наиболее прямолинейный путь — создание таблицы имен и соответствующих им указателей:
int function1(), function2();
struct {char *name; int (*funcptr)();    } symtab[] = { «function1»,      function1, «function2»,      function2, };
Ну а теперь нужно поискать в таблице нужное имя    и вызвать функцию, используя связанный с именем указатель.    См. также вопросы 9.9 и    16.11.

17.7    У меня,    кажется, нет головного файла <sgtty.h>.    Пришлите мне его, пожалуйста.

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

17.8    Как вызвать процедуры, написанные на языке FORTRAN (C++,BASIC,Pascal, Ada, Lisp) из С    (и наоборот).

О:    Ответ полностью    зависит    от машины и от специфики передачи параметров различными компиляторами. Решения вообще может не быть.    Внимательно читайте    руководство по компилятору. Иногда в документации имеется «Руководство по    смешанному программированию», хотя техника передачи аргументов и обеспечения правильного входа в функцию зачастую весьма таинственна. Дополнительная информация находится в файле FORT.gz Глена Гирса, (Glenn Geers) который можно получить с помощью ftp suphys.physics.su.oz.au в директории src.
Головной файл cfortran.h упрощает взаимодействие C/FORTRAN на многих популярных машинах. cfortran.h можно получит через ftp zebra.desy.de (131.169.2.244).
В C++ модификатор «C» внешней функции показывает, что функция будет вызываться с использованием соглашения о передаче параметров языка С.

17.9    Кто-нибудь знает о программах, переводящих Pascal или FORTRAN (или LISP, Ada, awk, «старый» С) в С?

О:    Есть несколько общедоступных программ:
p2c    Переводчик с Паскаля на    С, написанный  Дейвом Гиллеспи, (Dave Gillespie) помещен в comp.sources.unix в Марте 1990 (Volume 21); доступен также через ftp csvax.cs.caltech.edu, файл pub/p2c-1.20.tar.Z .
ptoc    Другой переводчик с Паскаля на С, написан на Паскале (comp.sources.unix, Volume 10, поправки    в vol. 13?)
f2c    Переводчик с фортрана на С совместно разработанный Bell Labs, Bellcore, and Carnegie Mellon. Подробности можно получить,    послав электронной почтой сообщение «send index from f2c» по адресу     netlib@research.att.com или research!netlib. (Эти подробности можно получить    и через    ftp netlib.att.com,    в директории netlib/f2c.)
Составитель этого списка вопросов и ответов имеет список других коммерческих трансляторов, среди них трансляторы для менее известных языков.  См. также вопрос 5.3.

17.10    Правда ли, что C++ — надмножество С. Можно ли использовать компилятор C++ для трансляции C    программ?

О:    С++ вырос из С и в большой степени базируется на нем, но некоторые правильные конструкции С недопустимы в C++. (Многие С программы, будут, тем не менее, правильно транслироваться компилятором С++).

17.11 ——-

17.12    Где найти все эти общедоступные    программы?

О:    Если у Вас есть    доступ к Usenet, смотрите периодически помещаемые сообщения  в comp.sources.unix и comp.sources.misc, которые описывают некоторые детали ведения архивов и подсказывают, как получить те или иные файлы.    Обычно используется ftp    и/или uucp c центральным, ориентированным    на пользователей сервером, таким как uunet (ftp.uu.net, 192.48.96.9). Однако, в этих вопросах и ответах невозможно исследовать или  перечислить все архивные серверы и рассказать о доступе к ним.
Ай Ша (Ajay Shah) поддерживает список общедоступных программ в области    численного анализа, который периодически публикуется, и его можно найти там же, где и    данные вопросы и ответы    (см. вопрос 17.33). Группа Usenet comp.archives содержит многочисленные объявления о том, что доступно на различных ftp. Почтовый сервер «archie» может подсказать, на каком ftp    имеются    те или иные программы. Пошлите почтовое сообщение «help» по адресу archie@quiche.cs.mcgill.ca для получения дальнейших инструкций. Наконец, группа comp.sources.wanted — обычно самое подходящее место, где можно поместить соответствующий запрос, но посмотрите прежде _их_ список вопросов и ответов (FAQ) «Как найти источники».

17.13    Где состоятся следующие    Соревнования по    Непонятному С Программированию (International    Obfuscated C Code Contest — IOCCC)? Как получить программы,    победившие в текущем и прошлых конкурсах?

О:      Соревнования обычно проходят с начала марта до середины мая. Для получения правил и рекомендаций, касающихся участия в конкурсе, пошлите электронной почтой письмо по адресу:
{apple,pyramid,sun,uunet}!hoptoad!judges  или judges@toad.com
,в разделе Subject которого напишите «send rules». Имейте в виду, что это _не_ адрес, куда    нужно посылать конкурсные программы.
Победители конкурса сначала объявляются на летней конференции Usenix (Summer Usenix Conference) в середине июня и становятся доступными в сети где-то в июле-августе. Программы-победители прошлых    конкурсов (начиная с 1984 г.) заархивированы в uunet (см. вопрос 17.12) в    директории ~/pub/ioccc.
В крайнем случае программы-победители прошлых конкурсов    можно получить, послав по указанному выше адресу письмо в графе Subject которого нужно указать:    «send YEAR winners», где YEAR —    год, представленный четырьмя    цифрами, интервал в несколько лет или «all».

17.14    Почему недопустимы вложенные комментарии? Как прикажете «выключить» фрагмент программы,    в котором уже есть комментарии? Можно ли использовать комментарии внутри стринговых констант?

О:    Вложенные комментарии принесут больше вреда, чем пользы, главным образом    из-за возможности случайно не закрыть комментарий, оставив внутри него символы «/*». По этой причине лучше    «выключить» большой фрагмент программы, в котором уже есть комментарии, с помощью средств препроцессора #ifdef или #if 0 (но имейте в виду вопрос    5.11).
Последовательность символов /* и */ не имеет специального значения внутри заключенных в двойные кавычки стрингов. Эта последовательность не рассматривается как комментарий, поскольку программа    (особенно та, которая создает текст другой С програмы) должна иметь возможность эти    комментарии печатать.
Смотри: ANSI Appendix E p. 198, Rationale Разд. 3.1.9 p. 33.

17.15    Как получить значение кода ASCII той или иной литеры, и    наоборот?

О:    В С литеры представлены    целыми числами,    соответствующими их значениям. (в соответствии    с набором символов данной машины). Так что нет необходимости в    преобразовании:    если известна литера, то известно и ее значение.

17.16    Как реализовать    последовательности и/или массивы бит?

О:    Используйте массивы переменных типа char или int и несколько макросов для операций с    отдельными битами (используйте определение 8 для CHAR_BIT,    если нет головного файла <limits.h>:

#include <limits.h>           /* для CHAR_BIT */
#define BITMASK(bit)    (1 << ((bit) % CHAR_BIT)) #define BITSLOT(bit)    ((bit) / CHAR_BIT) #define BITSET(ary, bit) ((ary)[BITSLOT(bit)] |= BITMASK(bit)) #define BITTEST(ary,    bit) ((ary)[BITSLOT(bit)] & BITMASK(bit))

17.17    Как наилучшим образом определить число установленных бит, соответствующих    определенному значению?

О:    Решение    этой и многих других проблем из    области    битоверчения можно ускорить и сделать более эффективным с помощью таблиц перекодировки. (но имейте в виду следующий вопрос).

17.18   Как повысить эффективность работы программы?

О:    Тема эффективности, очень часто    затрагиваемая в    comp.lang.c, не так важна как многие    склонны    думать.    Большая    часть кода в большинстве программ не    влияет на время    исполнения. Если время, занимаемое каким-то участком кода, мало    по сравнению с общим временем исполнения, то    для этого участка гораздо важнее простота и мобильность, чем эффективность. (Помните, что    компьютеры очень, очень быстры и даже «неэффективный» участок кода может выполняться без видимой задержки).
Печально известны попытки предсказать «горячие точки» программы. Когда эффективность программы имеет значение, важно использовать профилировщики для определения тех участков программы, которые заслуживают внимания. Часто основное время выполнения поглощается периферийными операциями, такими как ввод/вывод    и выделение памяти, которые можно ускорить с помощью буферизации и хеширования.
Для небольших участков программы, критичных в смысле эффективности, жизненно важно выбрать подходящий алгоритм; «микрооптимизация» этого участка менее важна. Многие часто    предлагаемые «приемы по увеличению эффективности» (вроде замены    операции сдвига    умножением на степень двойки) выполняются автоматически даже неизощренными компиляторами.
Неуклюжие попытки оптимизации способны так увеличить размер программы, что ее эффективность    упадет.
Дальнейшее обсуждение противоречий, связанных с эффективностью, а так же хорошие советы по увеличению эффективности, когда это важно, смотрите в главе 7 книги Кернигана и Плоджера «Элементы стиля программирования», а также в книге Джона Бентли «Написание эффективных программ».

17.19    Правда ли, что применение указателей более эффективно, чем применение массивов? Насколько замедляет программу вызов функции? Быстрее ли ++i чем i = i + 1?

О:    Точные ответы на эти и многие другие похожие вопросы, конечно же, зависят    от процессора и    применяемого компилятора. Если знать это необходимо, придется аккуратно определить время    выполнения тестовых программ. (Часто различия столь незначительны, что потребуются сотни тысяч повторений, чтобы их увидеть. Если есть возможность, посмотрите ассемблерный листинг, выдаваемый компилятором, чтобы убедиться в различной трансляции двух претендующих на первенство альтернатив).
«Обычно» быстрее продвигаться по большим массивам с помощью указателей, чем    с помощью индексов, однако есть    процессоры, для которых    справедливо обратное.
Хотя вызовы функций и увеличивают время    выполнения, сами функции настолько повышают модульность и простоту понимания программы, что едва ли полезно от них отказываться.
Прежде чем переписывать    выражения типа i=i+1, вспомните, что имеете дело с компилятором С а    не с программируемым калькулятором. Любой приличный компилятор будет одинаково транслировать ++i,i+=1; i=i+1. Использовать ++i, i+=1 или i=i+1 — вопрос стиля, не эффективности. (См. также вопрос 4.7).

17.20    Почему не выполняется такой фрагмент?
char *p = «Hello, world!»; p[0] = tolower(p[0]);

О:    Стринговые константы не    всегда можно модифицировать, за    исключением случая,    когда ими инициализируется массив. Попробуйте
char a[] = «Hello, world!»;
(Для компиляции старых программ некоторые компиляторы имеют ключ, который    управляет возможностью модификации стринговых констант.) См. также вопросы 2.1,2.2, 2.8 и 17.2.
Смотри: ANSI Разд. 3.1.4 .

17.21   Моя программа аварийно завершается еще до выполнения! (если использовать отладчик, то видно, что смерть наступает еще до выполнения первой инструкции в main).

О:    Видимо,    у Вас один или несколько очень больших (более килобайта) локальных массивов. Во многих системах размер стека фиксирован, а операционные системы, в которых осуществляется динамическое выделение стековой памяти, (например, UNIX) могут быть введены в заблуждение, когда размер стека  резко увеличивается.
Часто предпочтительнее объявить большие массивы типа static(если, конечно, каждый    раз при    рекурсивном вызове не требуется    свежий массив).
(См. также вопрос 9.4).

17.22    Что означают сообщения «Segmentation violation»    и «Bus error» ?

О:    Это значит, что    программа пытается получить доступ к несуществующей или запрещенной    для нее    области    памяти.    Это постоянно происходит из-за неинициализированных или неверно инициалированных указателей (см. вопросы 3.1, 3.2), по вине malloc (см. вопрос 17.23) или, может быть, scanf (см. вопрос 11.3).

17.23    Моя программа аварийно завершается, очевидно, при выполнении malloc, но я не    вижу в ней ничего плохого.

О:    К несчастью, очень легко разрушить внутренние структуры    данных, создаваемые malloc, а возникающие проблемы могут быть трудны для отладки. Чаще всего проблемы возникают при попытке записать больше данных,    чем может уместиться в памяти, выделенной malloc; особенно распространена ошибка malloc(strlen(s))    вместо strlen(s) + 1. Другие проблемы    включают освобождение указателей, полученных не в результате выполнения    malloc,    или попытки применить функцию realloc    к нулевому указателю. (см. вопрос 3.12).
Существует несколько отладочных    пакетов, чтобы помочь отследить возникающие при    применении malloc проблемы. Один из популярных — «dbmalloc» Конора П. Кахилла, (Conor P. Cahill) помещенный в comp.sources.misc в сентябре 1992. Другие — это «leak» помещенный в том 27 архива comp.sources.unix, JMalloc.c и JMalloc.h в сборике Fidonet Snippets (ищите с помощью archie; см. также вопрос 17.2); и MEMDEBUG — см. ftp.crpht.lu в pub/sources/memdebug . См. также вопрос 17.12.

17.24    Есть у кого-нибудь комплект тестов для С компилятора?

О:      Плюм Холл (Plum Hall) (ранее работавший в Кардифе, Нью Джерси, теперь Гаваи) продает такой комплект. Дистрибутив GNU C (gcc) от FSF включает c-torture-test.tar.Z который выявляет многие проблемы, возникающие при использованиии компиляторов. Тест Кагана (Kahan) под названием paranoia, который находится в директории netlib/paranoia на netlib.att.com интенсивно тестирует операции с плавающей точкой.

17.25    Где достать грамматику С для программы YACC?

О:    Самая надежная — конечно же грамматика из стандарта ANSI. Другая грамматика, подготовленная Джимом Роскиндом (Jim Roskind), находится на ics.uci.edu в директории pub/*grammar*.  Одетый в плоть, работающий образец ANSI грамматики (принадлежащий Джефу Ли(Jeff Lee)) находится на uunet (см. вопрос 17.12) в директории usenet/net.sources/ansi.c.grammar.Z (вместе с лексическим анализатором). В компиляторе GNU C от FSF есть грамматика, так же как есть она в приложении к книге K&R II.
Смотри: ANSI Разд. A.2 .

17.26    Мне необходим исходный текст для разбора и вычисления формул.

О:      Есть два доступных пакета —  «defunc» , помещенный в comp.source.misc в декабре 1993 г. (V41 i32,33),    в alt.sources в    январе 1994 г., его можно получить через ftp sunsite.unc.edu в директории pub/packages/development/libraries/defunc-1.3.tar.Z; и пакет «parse» в    lamont.ldgo.columbia.edu.

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

О:    Обычно такие сравнения включают    алгоритм «soundex», который ставит в соответствие сходно звучащим словам один и тот же числовой код.  Этот алгоритм описан в томе «Сортировка и поиск» классической книги Дональда Кнута «Искусство программирования для ЭВМ».

17.28    Как по дате найти день недели?

О:    Используйте mktime (см.    вопросы    12.6 и 12.7) или соотношение Зеллера (Zeller), или попробуйте вот эту функцию, помещенную Томохико Сакамото (Tomohiko Sakamoto):
dayofweek(y, m, d)      /* 0 = Воскресенье */ int y, m, d;            /* 1 <= m <= 12,  y > 1752 (примерно) */ { static int t[] =    {0, 3, 2, 5, 0,    3, 5, 1, 4, 6, 2, 4}; y -= m <    3; return (y + y/4 — y/100 + y/400 + t[m-1]    + d) % 7; }

17.29    2000-й год будет високосным? (год %4 ==0) —  правильный    тест на високосный год?

О:      Да и нет соответственно. Вот полной тест для Григорианского календаря:
year %    4 == 0 && (year    % 100 != 0 || year % 400 == 0)

17.30    Как произносить    «char»?

О:    Ключевое слово С «char»    можно произносит тремя способами: как английские слова «char,» «care,» or «car;». Выбор за Вами.

17.31    Какие есть хорошие книги для изучения С?

О:    Митч Райт (Mitch Wright) поддерживает аннотированную библиографию книг по    С и по UNIX; она доступна через    ftp ftp.rahul.net  в директории pub/mitch/YABL.

17.32    Можно ли получить книги    по С через Интернет?

О:    Можно, по крайней мере,    две:
«Notes    for C programmers,» Кристофера Соутелла, (Christopher Sawtell) доступна через svr-ftp.eng.cam.ac.uk:misc/sawtell_C.shar garbo.uwasa.fi:/pc/c-lang/c-lesson.zip paris7.jussieu.fr:/contributions/docs
«C for Programmers,» Тима Лова (Tim Love) доступна через svr-ftp.eng.cam.ac.uk    в директории misc.

17.33   Где найти другие варианты этих вопросов и ответов? Доступны ли более ранние редакции?

О:      Пошарьте по Сети. Обычно эти вопросы и ответы помещаются в comp.lang.c первого числа каждого месяца, со значением поля Expires, позволяющим присутствовать в comp.lang.c весь месяц. Там же есть сокращенная версия, представляющая собой список изменений, сопровождающий существенно обновленную версию. Такие списки можно так же найти в comp.answers и news.answers. Несколько серверов ведут архивы сообщений, помещаемых в news.answers, а также списков часто задаваемых вопросов (FAQ), включая и этот. Вот два сервера rtfm.mit.edu (директории pub/usenet/news.answers/C-faq/ и pub/usenet/comp.lang.c/ ) и ftp.uu.net (директорий usenet/news.answers/C-faq/ ).  Сервер archie должен помочь найти другие архивы; сделайти запрос на «prog C-faq». Дополнительную информацию можно найти в списке meta-FAQ в news.answers; см. также вопрос 17.12.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *