Программирование >>  Арифметические и логические операции 

1 ... 44 45 46 [ 47 ] 48 49 50 ... 53


есть, память, выделенная alloca, локальна по отношению к стековому кадру или контексту данной функции.

Использование alloca не может быть мобильным, реализации этой функции трудны на машинах без стека. Использование этой функции проблематично (и очевидная реализация на машинах со стеком не удается), когда возвращаемое ей значение непосредственно передается другой функции, как, например, в fgets(alloca(100), 100, stdin).

По изложенным выше причинам alloca (вне зависимости от того, насколько это может быть полезно) нельзя использовать в программах, которые должны быть в высокой степени мобильны.

Почему вот такой код: a(i) = не работает?

Подвыражение i++ приводит к побочному эффекту - значение i изменяется, что приводит к неопределенности, если i уже встречается в том же выражении.

Пропустив код int i = 7; printf( %d\n , i++ * через свой компилятор, я получил на выходе 49. А разве, независимо от порядка вычислений, результат не должен быть равен 56?

Хотя при использовании постфиксной формы операторов ++ и -увеличение и уменьшение выполняется после того как первоначальное значение использовано, тайный смысл слова после часто понимается неверно. Не гарантируется, что увеличение или уменьшение будет выполнено немедленно после использования первоначального значения перед тем как будет вычислена любая другая часть выражения. Просто гарантируется, что изменение будет произведено в какой-то момент до окончания вычисления (перед следующей точкой последовательности в терминах ANSI C). В приведенном примере компилятор умножил предыдущее значение само на себя и затем дважды увеличил i на 1.

Поведение кода, содержащего многочисленные двусмысленные побочные эффекты не определено. Даже не пытайтесь выяснить, как ваш компилятор все это делает (в противоположность неумным упражнениям во многих книгах по С).

Я экспериментировал с кодом: int i = 2; i = i++; Некоторые компиляторы выдавали i=2, некоторые 3, но один выдал 4. Я знаю, что поведение не определено, но как можно получить 4?

Неопределенное (undefined) поведение означает, что может случиться все что угодно.

Люди твердят, что поведение не определено, а я попробовал ANSI-компилятор и получил то, что ожидал

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

Могу я использовать круглые скобки, чтобы обеспечить нужный мне порядок вычислений? Если нет, то разве приоритет операторов не обеспечивает этого?

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

f() + g() * h() .

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

Тогда как насчет операторов &&, 11 и запятой? Я имею в виду код типа if((c = getchar()) == EOF 11 c == \n)

Для этих операторов, как и для оператора ?: существует специальное исключение; каждый из них подразумевает определенный порядок вычислений, т.е. гарантируется вычисление слева-направо.

Если я не использую значение выражения, то как я должен увеличивать переменную i: так: ++i или так: i++?

Применение той или иной формы сказывается только на значении выражения, обе формы полностью эквивалентны, когда требуются только их побочные эффекты.

Почему неправильно работает код: int a = 1000, b = 1000; long int c =

a * b;

Согласно общим правилам преобразования типов языка Си, умножение выполняется с использованием целочисленной арифметики, и результат может привести к переполнению и/или усечен до того как будет присвоен стоящей слева переменной типа long int. Используйте явное приведение типов, чтобы включить арифметику длинных целых:

long int c = (long int)a * b;

Заметьте, что код (long int)(a * b) не приведет к желаемому результату.



Что такое стандарт ANSI C?

В 1983 году Американский институт национальных стандартов (ANSI) учредил комитет X3J11, чтобы разработать стандарт языка Си. После длительной и трудной работы, включающей выпуск нескольких публичных отчетов, работа комитета завершилась 14 декабря 1989 г.со-зданием стандарта ANS X3.159-1989. Стандарт был опубликован весной 1990 г.

В большинстве случаев ANSI C узаконил уже существующую практику и сделал несколько заимствований из С+ + (наиболее важное - введение прототипов функций). Была также добавлена поддержка национальных наборов символов (включая подвергшиеся наибольшим нападкам трехзнаковые последовательности). Стандарт ANSI C формализовал также стандартную библиотеку.

Опубликованный стандарт включает Комментарии ( Rationa-le ), в которых объясняются многие решения и обсуждаются многие тонкие вопросы, включая несколько затронутых здесь. ( Комментарии не входят в стандарт ANSI X3.159-1989, они приводятся в качестве дополнительной информации.)

Стандарт ANSI был принят в качестве международного стандарта ISO/IEC 9899:1990, хотя нумерация разделов иная (разделы 2-4 стандарта ANSI соответствуют разделам 5-7 стандарта ISO), раздел Комментарии не был включен.

Как получить копию Стандарта?

ANSI X3.159 был официально заменен стандартом ISO 9899. Копию стандарта можно получить по адресу:

American National Standards Institute

11 W. 42nd St., 13th floor

New York, NY 10036 USA (+1) 212 642 4900

Global Engineering Documents

2805 McGaw Avenue

Irvine, CA 92714 USA

(+1) 714 261 1455

(800) 854 7179 (U.S. & Canada)

В других странах свяжитесь с местным комитетом по стандартам или обратитесь в Национальный Комитет по Стандартам в Женеве:

ISO Sales

Case Postale 56 CH-1211 Geneve 20 Switzerland

Есть ли у кого-нибудь утилиты для перевода С-программ, написанных в старом стиле, в ANSI C и наоборот? Существуют ли программы для автоматического создания прототипов?

Две программы, protoize и unprotoize осуществляют преобразование в обе стороны между функциями, записанными в новом стиле с прототипами, и функциями, записанными в старом стиле. (Эти программы не поддерживают полный перевод между классическим и ANSI C).

Упомянутые программы были сначала вставками в FSF GNU компилятор С, gcc, но теперь они - часть дистрибутива gcc.

Программа unproto - это фильтр, располагающийся между препроцессором и следующим проходом компилятора - на лету переводит большинство особенностей ANSI C в традиционный Си.

GNU пакет GhostScript содержит маленькую программу ansi2knr.

Есть несколько генераторов прототипов, многие из них - модификации программы lint. Версия 3 программы CPROTO была помещена в конференцию 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 **?

Можно использовать указатель-на-Т любых типов Т, когда ожидается указатель-на-const-T, но правило (точно определенное исключение из него), разрешающее незначительные отличия в указателях, не может применяться рекурсивно, а только на самом верхнем уровне.

Необходимо использовать точное приведение типов (т.е. в данном случае (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. Определение будет завершено объявлением структуры внутри прототипа.

У меня возникают странные сообщения об ошибках внутри кода, выключенного с помощью #ifdef

Согласно ANSI C, текст, выключенный с помощью #if, #ifdef или #ifndef должен состоять из корректных единиц препроцессирования .

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

Внутри кавычек не должно быть символов новой строки. Следовательно, комментарии и псевдокод всегда должны находиться между не-



1 ... 44 45 46 [ 47 ] 48 49 50 ... 53

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика