Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Язык C. Ч3.docx
Скачиваний:
2
Добавлен:
01.07.2025
Размер:
254 Кб
Скачать
☆

Int main(void)

{

char ch;

printf("Введите какой-нибудь символ.\n");

scanf ("%c", Sch); /* пользователь вводит символ */

printf("Код символа %c равен %d.\ n", ch, ch);

return 0;

}

Вот пример выполнения этой программы:

Введите какой-нибудь символ.

С

Код символа С равен 67.

При работе с программой не забывайте нажимать клавишу <Enter> или <Return> после ввода символа. Функция scanf () затем извлекает символ, введенный с клавиа­туры, а амперсанд (&) означает, что этот символ присваивается переменной ch. Далее с помощью функции printf () значение переменной ch выводится два раза, сначала как символ (на что указывает спецификатор %с), а потом как десятичное целое число (на что указывает спецификатор %d). Обратите внимание, что спецификаторы функ­ции printf () определяют способ отображения данных, но не то, как они хранятся в памяти (рис. 3.6).

Тип Bool

Тип Bool, появившийся в стандарте С99, применяется для представления булевских значений, т.е. логических значений true (истина) и false (ложь). Поскольку в языке С для представления true используется значение 1, а для представления false — значение 0, тип Bool по существу является целочисленным типом, но та­ким, который в принципе требует всего 1 бит памяти, поскольку этого достаточно, чтобы охватить весь диапазон от 0 до 1.

Переносимые типы: stdint.h И inttypes.h

К этому моменту вы, скорее всего, уже обратили внимание, что язык С предлагает широкое разнообразие целочисленных типов, и это можно только приветствовать. И, вероятно, вы также заметили, что одно и то же имя типа не обязательно означает одно и то же в разных системах, что не столь отрадно. Было бы замечательно, если бы язык С располагал типами, смысл которых не зависит от системы. Начиная со стандарта С99, нечто подобное было достигнуто.

Это было сделано в языке за счет создания дополнительных имен для существующих типов. Секрет в том, что эти новые имена определены в заголовочном файле stdint.h. Например, int32_t представляет тип для 32-битного целого значения со знаком. В системе, в которой используется 32-битный тип int, указанный заго­ловочный файл может определять int32_t в качестве псевдонима типа int. В дру­гой системе, где применяется 16-битный тип int и 32-битный тип long, это же имя, int32_t, может быть определено как псевдоним для типа long. Тогда при создании программы с использованием int32_t в качестве типа и включении заголовочного файла stdint.h компилятор будет заменять тип int или long так, как это подходит для конкретной системы.

Рассмотренные альтернативные имена являются примерами целочисленных типов с точной шириной. Тип int32_t содержит в точности 32 бита — ни больше и ни меньше. Не исключено, что целевая система не поддерживает эти варианты, так что целочис­ленные типы с точной шириной следует считать необязательными.

А что, если система не способна поддерживать типы с точной шириной? Стандарты С99 и СИ предоставляют вторую категорию альтернативных имен, которые являются обязательными. Этот набор имен гарантирует, что тип достаточно велик, чтобы удов­летворять спецификации, и нет других типов, которые могут выполнить нужную ра­боту, но имеют меньший размер. Эти типы называются типами с минимальной шириной. Например, int_least8_t представляет собой псевдоним наименьшего доступного типа, который может хранить 8-битное целочисленное значение со знаком. Если бы наименьший тип в конкретной системе был 16-битным, то тип int8_t не определялся бы. Однако тип int_least8_t был бы доступным и, скорее всего, реализованным как 16-битный целочисленный тип.

Конечно, есть программисты, которых больше заботит быстродействие, чем рас­ход памяти. Для них стандарты С99 и C11 определяют набор типов, которые обеспе­чат максимально быстрые вычисления. Эти типы называются высокоскоростными ти­пами с минимальной шириной. Например, тип int_fast8_t может быть определен как альтернативное имя для целочисленного типа данных вашей системы, который обес­печивает высокоскоростные вычисления с участием 8-битных значений со знаком.

Наконец, некоторых программистов устраивает только максимально возмож­ный в системе целочисленный тип; такому типу соответствует имя intmax_t и он может хранить любое допустимое целочисленное значение со знаком. Аналогично, uintmax_t представляет тип наибольшего допустимого целочисленного значения без знака. Кстати, указанные типы могут быть больше, чем long long и unsigned long, т.к. реализациям С разрешено определять типы, выходящие за рамки обязательных. Например, некоторые компиляторы ввели тип long long еще до того, как он стал частью стандарта.

Стандарты С99 и С11 не только предоставляют эти новые переносимые имена ти­пов, но также содействуют с вводом и выводом значений таких типов. Например, фун­кция printf () требует определенных спецификаторов для конкретных типов. В листинге 3.6 приведен краткий пример, иллюстрирующий применение переносимого типа и связанного с ним спецификато­ра. Заголовочный файл inttypes .h включает и файл заголовка stdint .h, поэтому в программе придется включать только файл inttypes.h.

Листинг 3.6. Программа altnames.c

/* altnames.c -- переносимые имена для целочисленных типов */

#include <stdio.h>

#include <inttypes.h> // поддерживает переносимые типы int main (void)

{

int32_t me32; // me32 -- это 32-битная переменная со знаком

me32 = 45933945;

printf("Сначала предположим, что int32_t является int: ");

printf("me32 = %d\n", те32);

printf("Далее не будем делать никаких предположений.\п") ;

printf("Вместо этого воспользуемся \"макросом\" из файла inttypes.h: ");

printf("me32 = %" PRId32 "\n", me32);

return 0;

}

Ниже показан вывод программы; обратите внимание, что в рассматриваемом при­мере также используется управляющая последовательность \" для отображения двой­ных кавычек:

Сначала предположим, что int32_t является int: rne32 = 45933945

Далее не будем делать никаких предположений.

Вместо этого воспользуемся "макросом" из файла inttypes.h: rne32 = 45933945

Типы float, double И long double

Разнообразные целочисленные типы нормально подходят для большинства про­ектов по разработке программного обеспечения. Тем не менее, ориентированные на математику и финансы программы часто оперируют числами с плавающей запятой. В языке С такие числа имеют тип float, double или long double. Они соответс­твуют данным вещественного типа в языках программирования FORTRAN и Pascal. Как упоминалось ранее, числа с плавающей запятой позволяют представлять намно­го больший диапазон чисел, включая десятичные дроби. Представление чисел с плавающей запятой подобно научной форме записи, которая применяется для выражения очень больших и очень маленьких чисел. Давайте рассмотрим такую форму записи.

В научной форме записи числа представляются в виде десятичных чисел, умножен­ных на степень числа 10. Рассмотрим несколько примеров.

Число

Научная форма записи

Экспоненциальная форма записи

1 ООО ООО ООО

1.0*105

1. 0е9

123 ООО

1.23*105

1.23е5

322,56

3.2256x10-'

3.2256е2

0,000056

5.6е-5

В первом столбце показана обычная форма записи числа, во втором столбце — на­учная форма записи, а в третьем — экспоненциальная форма записи, которая представ­ляет собой научную форму записи, обычно используемую при работе с компьютерами, при этом за обозначением «следует показатель степени 10. На рис. 3.7 приведено еще несколько примеров чисел с плавающей запятой.

Стандарт языка С требует, чтобы тип float был спосо­бен представлять минимум шесть значащих цифр и охваты­вал диапазон значений, по меньшей мере, от 10-37 до 10+37.

Первое требование означает, что тип float должен пред­ставлять, как минимум, первые шесть цифр такого числа, как 33.333333. Второе требование по достоинству оценят те, кто оперирует такими величинами, как масса Солнца (2.0е30 килограмм), электрический заряд протона (1.6е-19 кулона) или сумма государственного долга. Часто для хра­нения чисел с плавающей запятой системы используют 32 бита. Восемь битов отводятся под значение экспоненты и ее знака, а остальные 24 бита служат для представления не­экспоненциальной части числа, которая называется мантис­сой или значащей частью числа, и ее знака.

Для представления чисел с плавающей запятой язык С предлагает также тип double (обеспечивающий двойную точность). Тип double имеет те же требования к минималь­ному диапазону возможных значений, что и float, но под­держивает более высокое минимальное количество значащих цифр — 10. В типичных представлениях типа double применяются 64 бита, а не 32. В некоторых системах все 32 дополнительных бита используются для неэкспоненциальной части. Это приводит к увеличению количества значащих цифр и сокращению ошибок, связанных с округ­лением. В других системах часть этих битов используется для размещения большей экспоненты, благодаря чему расширяется диапазон возможных значений. Любой из этих подходов обеспечивает, как минимум, 13 значащих цифр, что более чем удовлет­воряет минимальному требованию стандарта.

Язык С допускает третий тип данных с плавающей запятой: long double. Цель этого типа — достижение большей точности, чем у типа double. Однако С гарантиру­ет только то, что точность типа long double, по меньшей мере, не уступает точности типа double.

Объявление переменных с плавающей запятой

Переменные с плавающей запятой объявляются и инициализируются гой же са­мой манере, что и переменные целочисленных типов. Ниже приведено несколько примеров:

float noah, jonah;

double trouble;

float planck = 6.63e-34;

long double gnp;

Константы с плавающей запятой (литералы)

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

-1.56Е + 12

2.87е-3

Знак “плюс” можно не указывать. Можно также опустить десятичную точку (2Е5) или экспоненциальную часть (19.28), но не то и другое одновременно. Можно обой­тись без дробной части (З.Е16) или целой части (.45Е-6), но не без обоих компонентов сразу. Ниже показано еще несколько допустимых констант с плавающей запятой:

3.14159

.2

4е16

. 8Е-5

100.

Не применяйте пробелы в константах с плавающей запятой. Например, эта конс­танта является недопустимой:

1.56 Е+12

По умолчанию компилятор предполагает, что константы с плавающей запятой име­ют тип double. Предположим, например, что some является переменной типа float, и есть следующий оператор:

some = 4.0 * 2.0;

Тогда значения 4.0 и 2.0 сохраняются как данные типа double с использованием для каждого (обычно) 64 бита. Произведение вычисляется с применением арифмети­ки с двойной точностью, и только после этого результат усекается к обычному типу float. Это гарантирует более высокую точность вычислений, но замедляет выполне­ние программы.

Язык С позволяет переопределить такое стандартное поведение компилятора за счет использования суффикса f или F, который заставляет компилятор трактовать константу с плавающей запятой как тип float, например, 2.3f и 9.11E9F. Суффикс 1 или L определяет число типа long double, например, 54.31 и 4.32e4L. Отметим, что букву L труднее перепугать с 1 (единица), чем букву 1. Если число с плавающей запятой не содержит суффикса, оно относится к типу double.

Вывод значений с плавающей запятой

Функция printf () использует спецификатор формата %f для вывода чисел типа float и double в десятичном представлении и спецификатор %е для вывода в экспо­ненциальном представлении. Если ваша система поддерживает шестнадцатеричный формат чисел с плавающей запятой, то вместо е или Е можно применять а или А. Для вывода данных типа long double требуются спецификаторы %Lf, %Le и %La. Обратите внимание, что для вывода как float, так и double используется специфи­катор %f, %е или %а. Причина в том, что язык С автоматически расширяет значения float до типа double, когда они передаются в качестве аргументов любой функции, такой как printf (), в прототипе которой тип аргумента не определен явным обра­зом. Это поведение демонстрируется в листинге 3.7.

/* showf_pt.c -- отображает значение типа float двумя способами */

#include <stdio.h>