Стив Саммит. Язык си в вопросах и ответах. Выражения.

Стив  Саммит. Язык си в вопросах и ответах. Выражения.

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

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

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

4. Выражения

5. ANSI C

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

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

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

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

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

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

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

13. Lint.

14. Стиль.

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

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

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

Выражения

4.1:    Почему вот такой код a[i] = i++; не работает?

О:      Подвыражение  i++  приводит к побочному эффекту —  значение  i изменяется, что    приводит к неопределенности, если i уже    встречается в том же выражении. (Обратите внимание на    то, что    хотя в книге K&R говорится, что поведение подобных выражений не описано, стандарт ANSI/ISO утверждает, что поведение не определено — см. вопрос 5.23.)

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

О:    Хотя  при  использовании постфиксной  формы  операторов     ++  и    — увеличение и уменьшение выполняется после того как первоначальное значение использовано, тайный смысл слова «после» часто    понимается неверно. _Не_ гарантируется,  что увеличение или уменьшение будет выполнено немедленно после использования первоначального значения перед тем как будет вычислена любая другая часть выражения. Просто гарантируется, что измение будет произведено в какой-то    момент до окончания вычисления (перед следующей «точкой последовательности» в терминах ANSI    C).  В приведенном примере компилятор умножил предыдущее значение само на себя и затем дважды    увеличил i на 1. Поведение кода,    содержащего  многочисленные двусмысленные побочные эффекты  неопределено  (см. вопрос 5.23). Даже не пытайтесь выяснить, как Ваш компилятор все это делает (в противоположность неумным упражнениям во многих книгах по С); в K&R мудро сказано: «Да хранит Вас Ваша невинность, если Вы не знаете, как это делается на разных машинах»

4.3:    Я экспериментировал с кодом

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

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

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

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

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

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

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

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

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

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

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

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

4.8    Почему    неправильно работает код

int a = 1000, b = 1000; long int c = a    * b;   ?

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

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

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

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

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