Иллюстрированный самоучитель по практике программирования

Язык

Порядок вычислений.
В С и C++ порядок вычислений операндов выражений, побочных эффектов и аргументов функций не определен. Например, в присваивании:

? n = (getcharQ " 8) getchar();

Второй getchar может быть вызван первым: порядок, в котором выражение записано, не обязательно соответствует порядку, в котором оно исполняется. В выражении:

? ptr[count] = name[++count];

Значение count может быть увеличено как до, так и после использования его в качестве индекса ptг, а в выражении:

? .printf("%c %c\n", getchar(), getchar());

Первый введенный символ может быть распечатан на втором месте, а не на первом. В выражении:

? printf("%f %s\n", logC-1.23), strerror(errno));

Значение errno может оказаться вычисленным до вызова log.

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

В Java порядок вычислений описан более жестко. В нем предусмотрено, что выражения, включая побочные выражения, вычисляются слева направо; правда, в одном авторитетном руководстве дан совет не писать кода, который бы "критично" зависел от этого порядка. Прислушаться к этому совету просто необходимо при создании программ, у которых есть хотя бы призрачный шанс конвертироваться в С или C++: как мы уже сказали, там нет никаких гарантий соблюдения такого же порядка. Конвертирование из одного языка в другой – экстремальный, но иногда весьма полезный тест на переносимость программы.

Наличие знака у char.
В С и C++ не определено, является ли char знаковым или беззнаковым типом данных. Это может привести к проблемам при использовании комбинаций char и int, как, например, в приводимом коде, где вызывается функция getchar(), возвращающая значение типа int. Если вы напишете:

?char с; /* должно было быть int */
? с = getchar();

То значение с будет в диапазоне от 0 до 255, если char – беззнаковый тип, и в диапазоне от – 128 до 127, если char – знаковый тип; речь идет о практически стандартной конфигурации с 8-битовыми символами на машинах с дополнительным до двух кодом. Это имеет особый смысл, если символ должен использоваться как индекс массива или для проверки на EOF, который в stdio обычно представляется значением -1. Например, представим, что мы разработали этот код из параграфа 6.1 после исправления некоторых граничных условий в начальной версии.

Сравнение s[i] == EOF никогда не будет истиной, если char – беззнаковый тип:

Иллюстрированный самоучитель по практике программирования › Переносимость › Язык

Когда getchar возвратит EOF, в s[i] будет сохранено значение 255 (OxFF, результат преобразования – 1 в unsigned char). Если s[i] беззнаковое, то при сравнении с EOF его значение останется 255, и, следовательно, проверка не пройдет.

Однако, даже если char является знаковым типом, код все равно некорректен. В этом случае сравнение с EOF будет проходить нормально, но при вводе вполне допустимого значения OxFF оно будет воспринято как EOF и цикл будет прерван. Так что вне зависимости от того, знаковый или беззнаковый у вас char, хранить значение, возвращаемое getchar, вы должны в int, и тогда проверка на конец файла будет осуществляться нормально. Вот как должен выглядеть наш цикл в переносимом виде:

Иллюстрированный самоучитель по практике программирования › Переносимость › Язык

В языке Java вообще нет спецификатора unsigned; порядковые типы данных являются знаковыми, а тип char (16-битовый) – беззнаковым.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.