Предельные значения н типы арифметических констант. 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Предельные значения н типы арифметических констант.



Символьных константs должны находиться в диапазоне от 0 до 255.

Для целых и вещественных констант каждая реализация компилятора с языка Си может определять свои ограничения.

В табл. 1.1 приведены пределы, исходя из которых компиляторы, реализованные на IBM-совместимых ПЭВМ, выбирают типы целых констант.

Целые константы н выбираемые для них типы

Диапазоны значений констант Тип данных
От О до 32767 int
от 32768 до 2147483647 loug
от 2147483648 до 4294967295 unsigned long
> 4294967295 ошибка

Данные вещественных типов

Тип данных Размер, бит Диапазон абсолютных величин
float   от 3.4Е-38 до 3.4Е+38
double   от1.7Е-308до1.7Е+308
long double   от3.4Е-4932до1.1Е+4932

Вещественная константа 3.141592653589793 будет воспринята как имеющая тип double, и ей будет выделено 8 байт (64 бита). Тот же тип выбирается для константы 3.14, так как по умолчанию всем вещественным константам присваивается тип double.

Если программиста не устраивает тип, который компилятор приписывает константе, то тип можно явно указать в записи константы с помощью суффиксов: F (или f) - float (для вещественных), U (или u) - unsigned (для целых), L (или l) - long (для целых и вещественных). Например:

3.14159F - константа типа float (выделяется 4 байта);

3.14L - константа типа long double (выделяется 10 байт).

С помощью суффикса U (или u) можно представить целую константу в виде беззнакового целого. Например:

50000U - константа типа unsigned int.

Константе 50000U выделяются 2 байта (вместо четырех, как было бы при отсутствии суффикса. В этом случае, т.е. для unsigned int, знаковый бит используется для представления одного из разрядов кода числа и диапазон значений становится от 0 до 65535.

Суффикс L (или l) позволяет выделить целой константе 4 байта (32 бита):

500L - константа типа long, которой выделяется 4 байта;

0L - целая константа типа long длиной 4 байта.

Совместное использование в любом порядке суффиксов U (или u) и L (или l) позволяет приписать целой константе тип unsigned long, и она займет в памяти 32 разряда (бита), причем знаковый разряд будет использоваться для представления раз­ряда кода (а не знака). Примеры:

0LU - целая константа типа unsigned long длиной 4 байта;

2424242424UL - константа типа unsigned long.

Нулевой указатель. Null-указатель, называемый нулевым указателем, это единственная неарифметическая константа. Ее роль и функциональные возможности станут ясны при изучении аппарата указателей. В конкретных реализациях null-указатель может быть представлен либо как 0, либо как 0L, либо как именованная константа NULL. Здесь нужно отметить, что значение константы NULL не обязано быть нулем и имеет право не совпадать с кодом символа '0'.

Константы перечисляемого типа. Целочисленные именованные константы можно вводить с помощью перечисления:

enum тип перечисления {список_именованных_констант};

где enum - служебное слово, вводящее перечисление;

тип перечисления - его название - необязательный про­извольный идентификатор;

список_именованных_констант - разделенная запятыми последовательность идентификаторов или именованных кон­стант вида:

имя_ константы=значение_константы

Примеры:

enum {ONE=1, TWO, THREE, FOUR};

enum DAY {SUNDAY, MONDAY, TUESDAY, WEDNESDAY,

THURSDAY, FRIDAY, SATURDAY};

enum BOOLEAN {NO, YES};

Если в списке нет ни одного элемента со знаком '=', то значе­ния констант начинаются с 0 и увеличиваются на 1 слева напра­во. Таким образом, N0 равно 0, YES равно 1, SUNDAY имеет значение 0 и FRIDAY имеет значение 5. Именованная константа со знаком '=' получает соответствующее значение (ONE=1), a следующие за ней именованные константы без явных значений увеличиваются на 1 каждая. В нашем примере TWO равно 2, THREE равно 3, FOUR равно 4.

Строки, или строковые константы. Формально строки (в соответствии, со стандартом) не относятся к константам языка Си, а представляют собой отдельный тип его лексем. Для них в литературе используется еще одно название "строковые литералы". Строковая константа определяется как последовательность символов, заключенная в двойные кавычки (не в апострофы):

"Образец строки"

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

"\n Текст \n разместится \n в 3-х строках дисплея"

 

Переменные

 

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

В соответствии с типами значений, допустимых в языке Си, рассмотрим символьные, целые и вещественные переменные автоматической памяти. Переменные автоматической памяти существуют в том блоке, где они определены. В наиболее распространенном случае таким блоком является текст основной (main) функции программы.

Простейшая форма определения переменных:

тип список_имен_переменных;

где имена переменных - это выбранные программистом идентификаторы, которые в списке разделяются запятыми;

тип - один из типов.

Определены целочисленны е типы:

char -целый длиной не менее 8 бит;

short int- короткий целый (допустима аббревиатура short);

int - целый;

long - длинный целый.

Каждый из целочисленных типов может быть определен либо как знаковый signed либо как беззнаковый unsigned (по умолчанию signed).

Различие между этими двумя типами - в правилах интерпретации старшего бита внутреннего представления. Спецификатор signed требует, чтобы старший бит внутреннего представления воспринимался как знаковый; unsigned означает, что старший бит внутреннего представления входит в код представляемого числового значения, которое считается в этом случае беззнаковым. Выбор знакового или беззнакового представления определяет предельные значения, которые можно представить с помощью описанной переменной. Например, на IBM PC переменная типа unsigned int позволяет представить числа от 0 до 65535, а переменной типа signed int (или просто int) соответствуют значения в диапазоне от -32768 до +32767.

Примеры определений целочисленных переменных:

char symbol, cc;

unsigned char code;

int number, row;

unsigned long long_number;

Обратите внимание на необходимость символа "точка с запятой" в конце каждого определения.

Стандартом языка введены следующие вещественные типы:

float - вещественный одинарной точности;

double - вещественный удвоенной точности;

long double- вещественный максимальной точности.

Значения всех вещественных типов в ЭВМ представляются с "плавающей точкой", т.е. с мантиссой и порядком,

Примеры определений вещественных переменных:

float х, X, ссЗ, pot_8;

double a, Stop, B4;

Инициализация переменных. В соответствии с синтаксисом языка переменные автоматической памяти после определения по умолчанию имеют неопределенные значения. Надеяться на то, что они равны, например, 0, нельзя. Однако переменным можно присваивать начальные значения, явно указывая их в определениях:

тип имя_ переменной=начальное значение;

Этот прием назван инициализацией. В отличие от присваивания, которое, осуществляется в процессе выполнения программы, инициализация выполняется при выделении для переменной участка памяти. Примеры определений с инициализацией:

float pi=3.1415, cc=1.23;

unsigned int. year=1997;

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

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

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

const тип имя_константы=значение_константы;

Здесь const - квалификатор типа, указывающий, что определяемый объект имеет постоянное значение, т.е. доступен только для чтения;

тип - один из типов объектов;

имя константы -идентификатор;

значение_константы должно соответствовать ее типу. Примеры:

const double Е=2.718282;

const long M=99999999;

const F=765;

В последнем определении тип константы не указан, по умолчанию ей приписывается тип int.

Третью возможность вводить именованные константы обеспечивает препроцессорная директива

#define имя_константы значение константы

Обратите внимание на отсутствие символа "точка с запятой" в конце директивы.

Отличие определения именованной константы

const double Е=2.718282;

от определения препроцессорной константы с таким же значением

#define EULER 2.718282

состоит внешне в том, что в определении константы Е явно задается ее тип, а при препроцессорном определении константы EULER ее тип определяется "внешним видом" значения константы. Например, следующее определение

#define NEXT 'Z'

вводит обозначение NEXT для символьной константы 'Z'. Это соответствует такому определению:

const char NEXT = 'Z';

Однако различия между обычной именованной константой и препроцессорной константой, вводимой директивой #define, гораздо глубже и принципиальнее. До начала компиляции текст программы на языке Си обрабатывается специальным компонентом транслятора - препроцессором. Если в тексте встречается директива

#define EULER 2.718282

а ниже ее в тексте используется имя константы EULER, например, в таком виде:

double mix = EULER;

d = alfa*EULER;

то препроцессор заменит каждое обозначение EULER на ее значение и сформирует такой текст:

double mix = 2.718282;

d = alfa*2.718282;

Далее текст от препроцессора поступает к компилятору, который уже "и не вспомнит" о существовании имени EULER, использованного в препроцессорной директиве #define. Константы, определяемые на препроцессорном уровне с помощью директивы #define, очень часто используются для задания размеров массивов, что будет продемонстрировано позже. Подстановка не выполняется в комментариях и в строковых константах.

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

FLT_MAX - максимальное число с плавающей точкой типа float;

CHAR_BIT- количество битов в байте;

INT_МIN - минимальное значение для данных типа int.

Чтобы использовать в программе указанные именованные препроцессорные константы, недостаточно записать их имена в программе. Предварительно в текст программы необходимо включить препроцессорную директиву такого вида:

#include <имя заголовочного _файла>

где в качестве имени заголовочного_файпа подставляются:

limits.h - для данных целых типов;

float.h - для вещественных данных.

#include <limits.h>

#include <float.h>

Операции

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

За исключением операций "[]", "()" и "?:", все знаки операций распознаются компилятором как отдельные лексемы. В зависимости от контекста одна и та же лексема может обозначать разные операции, т.е. один и тот же знак операции может употребляться в различных выражениях и по-разному интерпретироваться в зависимости от контекста. Например, бинарная операция & - это поразрядная конъюнкция, а унарная операция & - это операция получения адреса.

Операции ранга 1 имеют наивысший приоритет. Операции одного ранга имеют одинаковый приоритет, и если их в выражении несколько, то они выполняются в соответствии с правилом ассоциативности либо слева направо (→), либо справа налево (). Если один и тот же знак операции приведен в таблице дважды (например, знак *), то первое появление (с меньшим по номеру, т.е. старшим по приоритету, рангом) соответствует унарной операции, а второе - бинарной.

Опишем кратко возможности отдельных операций.

Приоритеты (ранги) операций

Ранг Операции Ассоциативность
  () [] → •
  ! ~ + - ++ -- & * (тип) sizeof  
  * / % (мультипликативные бинарные)
  + - (аддитивные бинарные)
  «» (поразрядного сдвига)
  < <= >= > (отношения)
  =!= (отношения)
  & (поразрядная конъюнкция "И")
  Ù (поразрядное исключающее "ИЛИ")
  | (поразрядная дизъюнкция "ИЛИ")
  && (конъюнкция "И")
  || (дизъюнкция "ИЛИ")
  ?: (условная операция)  
  = *= /= %= += -= &= Ùл= |= «=»=  
  , (операция "запятая")

Унарные (одноместные) операции. Для изображения одноместных префиксных и постфиксных операций используются следующие символы:

& - операция получения адреса операнда (ранг 2);

* - операция обращения по адресу, т.е. раскрытия ссылки, иначе операция разыменования (доступа по адресу к значению того объекта, на который указывает операнд). Операндом должен быть указатель (ранг 2);

- - унарный минус, изменяет знак арифметического операнда (ранг 2);

+ - унарный плюс, введен для симметрии с унарным минусом (ранг 2);

~ - поразрядное инвертирование внутреннего двоичного кода целочисленного аргумента - побитовое отрицание (ранг 2)\

!- НЕ - логическое отрицание значения операнда (ранг 2). Применяется к скалярным операндам. Целочисленный результат 0 (если операнд ненулевой, т.е. истинный) или 1 (если операнд нулевой, т.е. ложный). Напомним, что в качестве логических значений в языке используют целые числа: 0 - ложь и не нуль, т.е. (!0) - истина. Отрицанием любого ненулевого числа будет 0, а отрицанием нуля будет 1. Таким образом:!1 равно 0;!2 равно 0;!(-5) равно 0;!0 равно 1;

++ - увеличение на единицу (инкремент или автоувеличение -ранг 2).

-- - уменьшение на единицу (декремент или автоуменьшеие - ранг 2) - унарная операция, операндом которой должно быть леводопустимое выражение, т.е. не константа и не выражение:

sizeof - операция (ранг 2) вычисления размера (в байтах) для объекта того типа, который имеет операнд. Разрешены два формата операции:

sizeof выражение

sizeof (mun).

sizeof не вычисляет значения выражения, а только определяет его тип, для которого затем вычисляется размер.

Бинарные (двуместные) операции делятся на следующие группы:

• аддитивные;

• мультипликативные;

• сдвигов;

• поразрядные;

• операции отношений;

• логические;

• присваивания;

• выбора компонента структурированного объекта;

• операция "запятая";

• скобки в качестве операций.

Аддитивные операции:

+ - бинарный плюс - сложение арифметических операндов или сложение указателя с целочисленным операндом (ранг 4);

- - бинарный минус - вычитание арифметических операндов или вычитание указателей (ранг 4).

Мультипликативные операции:

* - умножение операндов арифметического типа (ранг 3);

/ - деление операндов арифметического типа (ранг 3). При целочисленных операндах абсолютное значение результата округляется до целого. Например, 20/3 рав­но 6, -20/3 равно -6, (-20)/3 равно -6, 20/(-3) равно -6;

% - получение остатка от деления целочисленных операндов (деление по модулю - ранг 3). При неотрицательных операндах остаток положительный. В противном случае остаток определяется реализацией. В компиляторе Turbo С:

13%4 равняется 1, (-13)%4 равняется -1; 13%(-4) равно +1, а (-13)%(-4) равняется -1.

При ненулевом делителе для целочисленных операндов всегда выполняется соотношение: (a/b)*b + a%b равно а.

Операции отношений (сравнения):

< меньше, чем (ранг 6);,

> больше, чем (ранг 6);

<= меньше или равно (ранг 6);

>= больше или равно (ранг б);

== равно (ранг 7);

!= не равно (ранг 7).

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

(х < В ==А < х) есть 1,

когда значение х находится в интервале от А до В и А<В либо х, А, В равны. (Вначале вычисляются х<В и А<х, к результатам применяется операция сравнения на равенство ==.)

Логические бинарные операции:

&& - конъюнкция (И) арифметических операндов или отношений (ранг 11. Целочисленный результат 0 (ложь) или 1 (истина);

|| - дизъюнкция (ИЛИ) арифметических операндов или отношений (ранг 12). Целочисленный результат 0 (ложь) или 1 (истина). (Вспомните о существовании унарной операции отрицания '!'.)

Результаты отношений и логических операций:

3<5 равняется 1;

3>5 равняется 0;

3=5 равняется 0;

3!=5 равняется 1;

3!=5 || 3=5 равняется 1;

3+4>5 && 3+5>4 && 4+5>3 равняется 1.

Операции присваивания (ранг 14)

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

Перечислим операции присваивания, отметив, что существуют одна простая операция присваивания и ряд составных операций:

= - простое присваивание: присвоить значение выражения-операнда из правой части операнду левой части. Пример: Р = 10.3 - 2*х;

*= - присваивание после умножения: присвоить операнду левой части произведение значений обоих операндов. Р *= 2 эквивалентно Р = Р * 2;

/= - присваивание после деления: присвоить операнду левой части частное от деления значения левого операнда на значение правого. Р /= 2.2 - d эквивалентно Р=- Р / (2.2 - d);

%= - присваивание после деления по модулю: присвоить операнду левой части остаток от целочисленного деления значения левого операнда на значение правого операнда. N %= 3 эквивалентно N = N % 3;

= - присваивание после суммирования: присвоить операнду левой части сумму значений обоих операндов А += В эквивалентно А = А + В;

-= - присваивание после вычитания: присвоить операнду левой части разность значений левого и правого операндов. X -= 4.3 - Z эквивалентно X = X - (4.3 - Z);

Обратите внимание, что для всех составных операций присваивания форма присваивания Е1 ор= Е2 эквивалентна Е1 = El op (E2), где ор - обозначение операции.

Запятая в качестве операции (ранг 15)

Несколько выражений, разделенных запятыми ",", вычисляются последовательно слева направо. В качестве результата сохраняются тип и значение самого правого выражения. Например, если переменная х имеет тип int, то значением выражения (х=3, 3*х) будет 9, а переменная х примет значение 3.

Условная трехместная операция (ранг 13). В отличие от унарных и бинарных операций условная тернарная операция используется с тремя операндами. В изображении условной операции применяются два символа '?' и ':' и три выражения-операнда:

выражение_1? выражение_2: выражение_3

Первым вычисляется значение выражения_1. Если оно истинно, т.е. не равно нулю, то вычисляется значение выражения_2, которое становится результатом. Если при вычислении выражения_1 получится 0, то в качестве результата берется значение выражения_3. Классический пример:

х < 0? -х: х;

Выражение возвращает абсолютную величину переменной х.

Операция явного преобразования типа. Операция преобразования (приведения) типа (ранг 2) имеет следующий формат:

(имя_типа) операнд

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

 

Разделители

 

Разделители, или знаки пунктуации, входят в число лексем языка:

[] () {},;: * = #

Квадратные скобки. Для ограничения индексов одно- и многомерных массивов, а также при записи индексированных элементов используются квадратные скобки [ ]. Примеры:

int A[5]; А -одномерный массив из пяти элементов;

int х, е[3][2]; е -двумерный массив (матрица) размером 3x2.

Выражение с индексированными элементами: е[0][0] = х= А[2] = 4; означает, что начальному элементу массива е, переменной х и третьему элементу массива А присваивается значение 4. Так как индексы в массивах всегда начинаются с 0, то элемент А[2] соответствует третьему элементу массива.

Круглые скобки. Назначение круглых скобок ():

1) выделяют выражения-условия (в операторе "если"):

if (х < 0) х = -х;

2) входят как обязательные элементы в определение и описание (в прототип) любой функции, где выделяют соответственно список формальных параметров и список спецификаций параметров:

float F(float x, int k) /* Определение функции*/

{ тело_функции }

float F(float, int); /* Описание функции – ее.прототип */

3) круглые скобки обязательны при определении указателя на функцию:

int (*pfunc)(); /* Определение указателя pfunc на функцию */

4) группируют выражения, изменяя естественную последовательность выполнения операций:

у = (а + b) / с; /*• Изменение приоритета операций */

5) входят как обязательные элементы в операторы циклов:

for (i=0, j=l; i<j; i+=2, j++) тело_цикла;

while (i<j) тело_цикла;

do тело_циклаwhile (k>0);

6) необходимы при явном преобразовании типа. Примеры:

long i = 12L; /* Определение переменной */

float brig; /* Определение переменной */

brig = (float)i; /* Явное приведение типа */

brig получает значение 12L, преобразованное к типу float;

Фигурные скобки. Для обозначения соответственно начала и конца составного оператора или блока используют фигурные скобки {}. Пример использования составного оператора в условном операторе:

if (d > x) { d--; x++; }

Пример блока - тело любой функции:

float absx (float x)

{

return x>0.0?x:-x;

}

Обратите внимание на отсутствие точки с запятой после закрывающейся скобки '}', обозначающей конец составного оператора или блока.

Фигурные скобки используются при инициализации массивов и структур при их определении:

/* Инициализация массива: */

int month [ ] ={ 1, 2, 3, 4, 5, б, 7, 8, 9, 10,11, 12 };

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

Другой пример списков - списки формальных и фактических параметров и их спецификаций в функциях.

Третье использование запятой как разделителя - в заголовке оператора цикла:

for (x=pl,y=p2,i=2; i<n; z=x+y; x=y, y=z, i++);

Запятая как разделитель используется также в описаниях и определениях объектов (например, переменных) одного типа:

Int i, n,-

float x, у, z, pi, p2;

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

int i=l, m[ ]={ i, (i=2,i*i), i };

В данном примере запятая в круглых скобках выступает в роли знака операции. Операция присваивания "=" имеет более высокий приоритет, чем операция "запятая". Поэтому вначале i получает значение 2, затем вычисляется произведение i*i, и этот результат служит значением выражения в скобках. Однако значением переменной i остается 2. Значениями m[0], m[1], m[2] будут соответственно 1, 4, 2.

Точка с запятой. Каждый оператор, каждое определение и каждое описание в программе на языке Си завершает точка с запятой ';'. Любое допустимое выражение, за которым следует ';', воспринимается как оператор. Это справедливо и для пустого выражения, т.е. отдельный символ "точка с запятой" считается пустым оператором. Пустой оператор иногда используется как тело цикла. Примеры операторов-выражений:

i++; /* Результат - только изменение Значения переменной i */

F(z,4); /* Результат определяется телом функции с именем F */

Двоеточие. Для отделения метки от помечаемого ею оператора используется двоеточие':':

метка: оператор;

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

int printf (const char * format,...); int scanf (const char * format,...);

Звездочка Звездочка '*' используется в качестве знака операции умножения и знака операции разыменования (получения доступа через указатель). В описаниях и определениях звездочка означает, что описывается (определяется) указатель на значение использованного в объявлении типа.

Обозначение присваивания. Для обозначения операции присваивания используется символ '='. Кроме того, в определении объекта он используется при его инициализации:

/* инициализация структуры */

struct {char x, int у} А={ 'z', 1918 };

/* инициализация переменной */

int F = 66;

Признак препроцессорных средств. Символ '#' используется для обозначения директив препроцессора. Например:

#include <stdio.h>

#define



Поделиться:


Последнее изменение этой страницы: 2017-02-10; просмотров: 259; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.145.163.58 (0.143 с.)