Выражения и присваивания


Операции в языке Си

Над объектами в языке Си могут выполняться различные операции:

  • операции присваивания;
  • операции отношения;
  • арифметические;
  • логические;
  • сдвиговые операции.

Результатом выполнения операции является число.

Операции могут быть бинарными или унарными.
Бинарные операции выполняются над двумя объектами, унарные — над одним.

Операция присваивания

Операция присваивания обозначается символом = и выполняется в 2 этапа:

  • вычисляется выражение в правой части;
  • результат присваивается операнду, стоящему в левой части:

объект = выражение;

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

Операции отношения

Основные операции отношения:

  • == эквивалентно — проверка на равенство;
  • != не равно — проверка на неравенство;
  • меньше;
  • > больше;
  • меньше или равно;
  • >= больше или равно.

Операции отношения используются при организации условий и ветвлений. Результатом этих операций является 1 бит, значение которого равно 1 , если результат выполнения операции — истина, и равно 0 , если результат выполнения операции — ложь.

Арифметические операции

Основные бинарные операции, расположенные в порядке уменьшения приоритета:

  • * — умножение;
  • / — деление;
  • + — сложение;
  • — вычитание;
  • % — остаток от целочисленного деления.

Основные унарные операции:

  • ++ — инкрементирование (увеличение на 1);
  • –– — декрементирование (уменьшение на 1);
  • — изменение знака.

Результат вычисления выражения, содержащего операции инкрементирования или декрементирования, зависит от того, где расположен знак операции (до объекта или после него). Если операция расположена до объекта, то сначала происходит изменение значения переменной на 1, а потом это значение используется для выполнения следующих операций. Если операция ++ или расположена после переменной, то сначала выполняется операция, а потом значение переменной изменяется на 1.

Бинарные арифметические операции могут быть объединены с операцией присваивания:

  • объект *= выражение; // объект = объект * выражение
  • объект /= выражение; // объект = объект / выражение
  • объект += выражение; // объект = объект + выражение
  • объект -= выражение; // объект = объект — выражение
  • объект %= выражение; // объект = объект % выражение

Логические операции

Логические операции делятся на две группы:

Условные логические операции чаще всего используются в операциях проверки условия if и могут выполняться над любыми объектами. Результат условной логической операции:

  • 1 если выражение истинно;
  • 0 если выражение ложно.

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

Основные условные логические операции:

  • && — И (бинарная) — требуется одновременное выполнение всех операций отношения;
  • || — ИЛИ (бинарная) — требуется выполнение хотя бы одной операции отношения;
  • ! — НЕ (унарная) — требуется невыполнение операции отношения.

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

Основные побитовые логические операции в языке Си:

инверсия (логическое НЕ) — унарная операция, результат которой равен 0 если операнд единичный, и равен 1, если операнд нулевой;

  • ^ исключающее ИЛИ — бинарная операция, результат которой равен 1, если только один из двух операндов равен 1 (в общем случае если во входном наборе операндов нечетное число единиц).
  • Для каждого бита результат выполнения операции будет получен в соответствии с таблицей.

    a

    a b a & b a | b a ^ b
    1
    1 1 1 1
    1 1 1
    1 1 1 1

    a; // e = 241 = 1111 0001
    f = a ^ b; // f = 7 = 0000 0111

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

    Бит Маска
    0x01
    1 0x02
    2 0x04
    3 0x08
    4 0x10
    5 0x20
    6 0x40
    7 0x80

    Для установки определенного бита необходимо соответствующий бит маски установить в 1 и произвести операцию побитового логического ИЛИ с константой, представляющей собой маску:

    Для сброса определенного бита необходимо соответствующий бит маски сбросить в 0 и произвести операцию побитового логического И с константой, представляющей собой инверсную маску:

    0x02); // a = 1, бит 1 сброшен

    Бинарные побитовые логические операции могут быть объединены с операцией присваивания:

    • объект &= выражение; // объект = объект & выражение
    • объект |= выражение; // объект = объект | выражение
    • объект ^= выражение; // объект = объект ^ выражение

    Сдвиговые операции

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

    • >> — сдвиг вправо;
    • — сдвиг влево.


    Общий синтаксис осуществления операции сдвига:
    объект = выражение сдвиг КоличествоРазрядов;

    Арифметический сдвиг целого числа вправо >> на 1 разряд соответствует делению числа на 2.
    Арифметический сдвиг целого числа влево на 1 разряд соответствует умножению числа на 2.

    Выражения и присваивания

    Операторы языка С обрабатывают один операнд (унарные операторы), два операнда (бинарные операторы) или три операнда (тернарный оператор). Операторы присвоения включают и унарные и бинарные операторы. Операторы присвоения рассматриваются в Разделе 5.4. Унарные операторы ставятся до их операндов и ассоциируются справа налево. В языке С имеются следующие унарные операторы:

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

    В языке С есть только один тернарный оператор условия (? :). Он ассоциируется справа налево. <Обычные арифметические преобразования >Большинство операторов С выполняют преобразование типа, чтобы привести операнды выражения к некоторому общему типу или для расширения коротких значений до размеров целого, который используется в машинных операциях. Выполняемые операторами С преобразования завмсят от конкретных операторов и типов операнда или операндов. Однако, многие операторы выполняют аналогичные преобразования над операндами целого типа и типа с плавающей точкой. Эти преобразования известны, как «арифметические преобразования», т.к. они применяются к типам значений, обычно используемым в арифметике. Арифметические преобразования, собранные в данном разделе, называются «обычными арифмитическими преобразованиями. При рассмотрении каждого оператора в последующих разделах оговаривается, выполняет ли данный оператор обычные арифмитические преобразования. Кроме того, указаны выполняемые оператором дополнительные арифметические преобразования, если они имеют место. Не задан какой-либо порядок следования. Он определяется следующим алгоритмом, который применяется к каждой бинарной операции в выражении:

    Все опернды типа float преобразуются в тип double.

    Если один операнд имеет тип long double, то и другой операнд преобразуется в тип long double.

    Если один операнд имеет тип double, то и другой операнд преобразуется в тип double.

    Все операнды типа char или short преобразуются в тип int.

    Все операнды типа unsigned char или unsigned short преобразуются в тип unsigned int.

    Если один операнд имеет тип unsigned long, то и другой операнд преобразуется в тип unsigned long.

    Если один операнд имеет тип long, то и другой операнд преобразуется в тип long.

    Если один операнд имеет тип unsigned int, то и другой операнд преобразуется в тип unsigned int.

    Следующий пример демонстрирует применение приведенного алгоритма:

    v Преобразование в данном примере будет проделано следующим образом:

    uc преобразуется в тип unsigned int (шаг 5).

    i преобразуется в тип unsigned int (шаг 8). Выполняется умножение и результатом будет тип unsigned int.

    uc*i преобразуется в тип long (шаг 7).

    Выполняется сложение и результатом будет тип long. <Дополнение и унарный плюс >Операторы дополнения рассматриваются в следующем списке:

    Примечание Оператор унарного плюса в Microsoft C реализован синтаксически, но не семантически для любого связанного с ним типа. Пример 1 В данном примере новое значение x есть отрицание 987, или -987.

    Пример 2 В данном примере y присваивается новое значение, которое является к величине без знака 0xaaaa, или 0x5555.

    Пример 3 В данном примере если x больше или равен y, то результат выражения есть 1 («истина»), а если x меньше y, то результат есть 0 («ложь»).

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

    Оператор адресации получает косвенный доступ к значению через указатель. Операнд должен быть значением указателя. Результатом будет значение по адресу операнда, т.е. операнд задает адрес, где хранится значение. Тип результата совпадает с типом операнда, задающего адрес. Если значение указателя некорректно, то результат будет неопределен. Условия некорректности значения указателя зависят от реализации. Следующий список содержит наиболее часто встречающиеся некорректные ситуации:

    Пойнтер задает адрес локального элемента, который не активен в момент ссылки на него.

    Пойнтер задает адрес, который не соответствует типу указанного объекта.

    Пойнтер задает адрес, который не используется выполняемой программой.

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

    Нельзы применять оператор получения адреса к компоненте битового поля структуры (см. Раздел 4.4.3, «Объявления структур») или к идентификатору, который объявлен со спецификатором класса хранения register (см. Радел 4.6). В Примерах от 1 до 4 используются следующие объявления:

    Пример 1 В данном примере оператор получения адреса (&) берет адрес шестого элемента массива a. Результат записывается в указатель pa.

    Пример 2 В данном примере оператор адресации (*) используется для получения доступа к значению int, которое хранится по адресу pa. Это значение присваивается целой переменной x.

    Пример 3 В данном примере будет напечатано слово True. Данный пример демонстрирует, что результат применения операции адресации к адресу x совпадает с x.

    Пример 4 В данном примере показано надлежащее применение правил, показанных в Примере 3. Сначала адрес x приведением типа преобразуется в указатель типа double, а затем применение оператора адресации дает результат типа double.

    Пример 5 В данном примере объявляется функция roundup, и объявляются и инициализируются два указателя на roundup. Первый указатель proundup инициализируется с использованием только имени функции, а второй, pround, использует при инициализации оператор получения адреса. Результаты инициализации совпадают.

    Оператор sizeof дает размер памяти в байтах, который связан с заданным идентификатором или типом. Этот оператор позволяет избежать задания в программе размеров данных, которые зависели бы от ЭВМ. Выражение sizeof имеет вид:

    Выражение является либо идентификатором, либо выражением приведения типа (т.е. заключееный в скобки спецификатор типа). Если это выражение приведения типа, оно не может быть void. Если это идентификатор, он не может представлять объект битового поля или имя функции. При применении оператора sizeof к идентификатору массива результатом будет размер массива, а не размер указателя, который соответствует идентификатору массива. При применении оператора sizeof к имени типа структуры или объединения или к идентификатору типа структуры или объединения, резутатом будет размер структуры или объединения. Этот размер может включать в себя внутреннее или хвостовое выравнивание границ по памяти компонент структуры или объединения. Т.о. результат может не соответствовать размеру, который вычисляется сложением выделяемых для каждой из компонент обрастей памяти. Пример 1 Данный пример использует оператор sizeof для передачи размера int, который у разных ЭВМ разный, в качестве аргумента в функцию calloc. buffer хранит возвращаемое функцией значение.

    Пример 2 В данном примере string это массив указателей на char. Число указателей это число элементов массива, но оно не задано. Используя оператор sizeof легко определить число указателей для определения числа элементов массива. Этим числом инициализуется const целое значение string_no. string_no нельзя модифицировать, т.к. это значение const.

    <Мультипликативные операторы >Мультипликативные операторы выполняют операции умножения (*), деления (/), и взятие остатка (%). Операнды оператора взятия остатка должны быть интегрального типа. Операторы умножения и деления могут обрабатывать целые операнды и операнды с плавающей точкой, при этом типы операндов могут быть разные. Мультипликативные операторы выполняют обычные арифметические преобразования над операндами. Тип результата совпадает с типами операндов после преобразования. Примечание Выполняемые мультипликативными операторами преобразования не делают какой-либо проверки на переполнение, поэтому может произойти потеря информации, если результат мультипликативной операции не может быть представлен типом операнда после преобразования. Мультипликативные операторы языка С могут быть описаны следующим образом:

    Данные объявления были использованы во всех последующих примерах данного раздела:

    Пример 1 В данном примере x умножается на i и дает в результате 20.0. Результат имеет тип double.

    Пример 2 В данном примере 10 делится на 3. Результат округляется до 0, давая целое значение 3.

    Пример 3 В данном примере n присваивается целый остаток от деления 10 на 3.

    <Аддитивнные операторы >Аддитивные операторы выполняют сложение (+) и вычитание (-). Операндами могут быть целые значения или значения с плавающей точкой. Некоторые аддитивные операции могут быть выполнены и над значениями указателей, как это подчеркивается при рассмотрении каждого оператора. Аддитивные операторы выполняют обычные арифметические преобразования интегральных операндов и операндов с плавающей точкой. Тип результата совпадает с типом операндов после их преобразования. Выполняемые аддитивными операторами преобразования не делают какой-либо проверки на переполнение, поэтому может произойти потеря информации, если результат аддитивной операции не может быть предствален типом операнда после преобразования. Сложение (+) Оператор сложения вызывает суммирование двух его операндов. Оба операнда могут быть интегральноги типа или типа с плавающей точкой, либо либо один операнд может быть указателем, а другой целой величиной. Когда к указателю добавляется целая величина (i) она преобразуется путем ее умножения на размер величины, на которую указывает указатель. После преобразования это целое значение представляет собой i-ую позицию памяти, а каждая позиция имеет длину, задаваемую типом указателя. При добавлении целого значения к значению указателя результатом будет новый указатель, значение котрого соответствует адресу i-ой позиции от первоначального адреса. Значение нового указателя есть адрес величины того же самого типа, на который указывал первоначальный указатель. Вычитание (-) Оператор вычитания (-) отнимает значение второго операнда из первого. С этим оператором могут быть использованы следующие комбинации операндов:

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

    Оба операнда являются указателями на один и тот же тип.

    Первый операнд это указатель, а второй — целая величина.

    При вычитании двух указателей, их разность преобразуется в целую велину со знаком, делением разности размеров значений, на которые они указывают. Результат будет соответствовать числу позиций памяти заданного типа между двумя адресами. Результат имеет смысл только для двух элементов одного и того же массива, как это будет рассмотрено позднее в данном разделе в «Арифметике указателей». Когда из указателя вычитается целая величина (i) она преобразуется путем ее умножения на размер величины, на которую указывает указатель. После преобразования это целое значение представляет собой i-ую позицию памяти, а каждая позиция имеет длину, задаваемую типом указателя. При вычитании целого значения из значения указателя результатом будет новый указатель, значение котрого соответствует адресу i-ой позиции до первоначального адреса. Значение нового указателя есть адрес величины того же самого типа, на который указывал первоначальный указатель. Арифметика указателей Аддитивные операции с указателем и целой велиной дают осмысленные результаты только в том случае, когда операнд-указатель задает адрес компоненты массива и целое значение задает сдвиг в пределах границ этого же массива. Когда целая величина преобразуется в сдвиг адреса, компилятор предполагает, что между первоначальным адресом и результирующим адресом расположены позиции памяти только одинакового размера. Это предположение справедливо для компонент массива. По своему определению массив это совокупность значений одного типа. Его компоненты располагаются неприрывно в заданной области памяти. Однако, нет гарантии, что элементы любого отличного от массива типа располагаются в памяти непрерывно. Т.е. между позициями памяти могут появляться пропуски, даже если каздая из позиций имеет одинаковый тип. Т.о. результаты добавления или уменьшения адресов любых величин, кроме элементов массива, не определены. Аналогично, при вычитании величин двух указателей , преобразование предполагает, что величины имеют один тип, между ними нет пропусков. Для ЭВМ сегментированной архитектуры (например, 8086/8088), аддитивные операции с указателем и целой величиной в некоторых случаях могут быть некорректными. Например, операция может дать в результате адрес, который находится вне границ массива. Дополнительная информация о моделях памяти содержится в Вашем Руководстве по компилятору. Данные объявления используются в двух последующих примерах:

    Пример 1 В данном примере значение i умножается на длину типа float и добавляется к &x[4]. В результате получаем указатель, который указывает на величину x[8].

    Пример 2 В данном примере адрес третьего элемента x (задаваемый x[i-2]) вычитается из адреса пятого элемента x (задаваемого x[i]). Разность делится на длину float и результатом будет целое значение 2.

    <Сдвиг >Операторы сдвига сдвигают свой первый операнд влево ( >) на число позиций, задаваемое вторым операндом. Оба операнда должны быть целыми значениями. Эти операторы выполняют обычные арифметические преобразования. Тип результата совпадает с типом левого операнда после преобразования. Сдвиг влево обращает правые биты в 0. При сдвиге вправо свободные левые биты заполняются в соответствии с типом первого операнда после преобразования. Если этот тип unsigned, то они устанавливаются в 0. В противном случае они заполняются копиями бита знака. Если второй операнд есть отрицательная величина, то результат операции сдвига не определен. Выполняемые операторами сдвига преобразования не делают какой-либо проверки на переполнение, поэтому может произойти потеря информации, если результат операции сдвига не может быть представлен типом первого операнда после преобразования. Пример

    В данном примере x сдвигается влево на восемь позиций, а y сдвигается вправо на восемь позиций. Сдвинутые значения складываются и результат, 0xaa55, присваивается z. <Отношения >Бинарные операторы отношений сравнивают первый операнд со вторым и проверяют истинность заданного соотношения. Результат проверяемого выражения отношения равен 1, если оно «истина», и равен 0, если оно «ложь». Результат имеет тип int. Имеются следующие операторы отношений:

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

    Оба операнда любого оператора отношений могут быть указателями на один и тот же тип. Для операторов равенства (==) и неравенства (!=) результат сравнения показывает, задают ли эти два указателя один и тот же адрес места в памяти. Для других операторов отношений ( , =) результат сравнения показывает относительную позицию двух адресов памяти. Адрес заданному значению выделяется случайно, поэтому сравнение адресов двух не связанных величин обычно не имеет смысла. Однако, может быть полезным сравнение адресов различных элементов одного и того же массива, т.к. гарантируется, что элементы массива хранятся в упорядоченной последовательности один за другим, от первого до последнего. Адрес первого элемента массива «меньше» адреса его последнего элемента.

    Значение указателя можно сравнить на совпадение (==) или на несовпадение (!=) с постоянной величиной 0. Пойнтер со значением 0 называется «пустым» указателем, и он не указывает ни на какую область памяти.

    Пример 1 Значения x и y равны, поэтому результатом выражения будет 0.

    Пример 2 Фрагмент данного примера инициализирует каждый элемент массива array пустой символьной константой.


    Пример 3 В данном примере объявляется перечислимая переменная с именем col и признаком color. В любой момент времени переменная может содержать целое значение 0, 1 или 2, которое соответствует одному из элементов перечислимого набора color: red, white или green, соответственно. Если col содержит 0, то выполняется оператор if и все операторы, выполнение которых связано с результатами выполнения if.

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

    В последующих примерах использованы следующие объявления:

    Пример 1 Результат, присвоенный n, совпадает с i (шестнадцатеричное 0xab00).

    Пример 2 Побитовое включающее-ИЛИ дает в результате 0xabcd (шестнадцатеричное).

    Пример 3 Побитовое исключающее-ИЛИ дает в результате 0xcd (шестнадцатеричное).

    <Логические операторы >Логические операторы выполняют операции логического-И (&&) и логического-ИЛИ (||). Операнды логических операций должны иметь интегральный тип, тип плавающей точки или тип указателя. Типы операндов могут быть разными. Выражения операндов логического-И и логического-ИЛИ вычисляются слева направо. Если значение первого операнда достаточно для определения результата операции, то второй операнд не вычисляется. После первого операнда есть точка упорядочевания. Логические операторы не проводят обычных арифметических преобразований. Вместо этого они вычисляют каждый операнд в категории его эквивалентности 0. Результат логической операции 0 или 1. Тип результата int. Логические операторы языка С описываются следующим образом:

    В последующих примерах использованы данные объявления:

    Пример 1 В данном примере вызывается функция printf для распечатки сообщения, если x меньше y, и y меньше z. Если x больше y, то второй операнд (y или .), если выбранная компонента не является вышеуказанным выражением.

    Выражение унарной адресации, которое не указывает массив или функцию.

    Выражение локализации в скобках.

    Объект const (немодифицируемое выражение локализации).

    <Унарное увеличение и уменьшение >Унарные операторы присвоения (++ и -\,-) соответственно увеличивают и уменьшают значения их операндов. Операнды должны быть интегрального типа, типа с плавающей точкой или типа указателя и должны быть модифицируемыми (не постоянными) выражениями локализации. Операнд интегрального типа или типа с плавающей точкой увеличивается или уменьшается на целую величину 1. Тип результата совпадает с типом операнда. Операнд типа указателя увеличивается или уменьшается на величину размера объекта, на который он указывает. Увеличенный указатель указывает на следующий объект, а уменьшенный — на предыдущий. Оператор увеличения (++) или уменьшения (-\,-) может появиться до или после операнда по следующим правилам:

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

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

    Пример 1 В данном примере переменная pos сравнивается с 0, а затем увеличивается. Если pos до увеличения была положительной величиной, то выполняется следующий оператор. Сначала значение q присваивается p, а затем значения q и p увеличиваются.

    Пример 2 В данном примере переменная i уменьшается до ее использования в качестве индекса line.

    <Простое присвоение >Оператор простого присвоения присваивает значение своего правого операнда левому операнду. Применимы правила преобразования для присвоений (см. Раздел 5.6.1). Пример В данном примере значение y преобразуется в тип double и присваивается x.

    <Составные присвоения >Операторы составного присвоения комбинируют оператор простого присвоения с другим бинарным оператором. Операторы составного присвоения выполняют операцию, заданную дополнительным оператором, а затем присваивают результат левому операнду. Например составное выражения типа

    следует понимать, как

    Однако, составные выражения присвоения не эквивалентны расширенной версии, т.к. выражение составного присвоения вычисляет выражение1 только один раз, а расширенная версия вычисляет выражение1 дважды: в операции сложения и в операции присвоения. Операнды оператора составного присвоения должны быть интегрального типа или типа с плавающей точкой. Каждый оператор составного присвоения выполняет преобразование так, как соответствующий бинарный оператор обрабатывает и ограничивает типы своих соответствующих операторов. Операторы присвоения со сложением (+=) и присвоения с вычитанием (-=) могут иметь левым операндом тип указателя, в этом случае правый операнд должен быть интегрального типа. Результат операции составного присвоения имеет значение и тип левого операнда. Пример В данном примере операция побитового включающего-ИЛИ выполняется над n и MASK, и результат присваивается n. Объявленная константа MASK определяется с директивой предпроцессора #define (данная директива рассматривается в Разделе 8.2.2.).

    Приоритет и порядок проведения операций

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

    Операторы приведены в списке по убыванию их приоритета. Если на одной строке расположено несколько операторов, то они имеют равный приоритет. Все унарные операторы имеют равный приоритет. Все простые и составные операторы присвоения имеют равный приоритет. Как это показано в Таблице 5.1, операнды, состоящие из константы, идентификатора, строки, вызова функции, выражения индекса, выражения выбора компоненты или выражения в скобках имеют наивысший приоритет и ассоциируются слева направо. Преобразования типа и имеют тот же приоритет и ассоциативность, что и унарные операторы. Выражения могут содержать несколько операторов с одинаковым приоритетом. Если несколько таких операторов появляются в выражении на одном уровне, то их вычисление производится в соответствии с ассоциативностью оператора либо справа налево, либо слева направо. Направление вычислений не влияет на результаты вычисления выражений, которые содержат несколько операторов сложения (+), умножения (*) или обработки бит (& | ^) на одном уровне. Компилятор может вычислять такие выражения в любом порядке, даже если для задания порядка вычислений в выражении заданы скобки. Точками упорядочивания являются только операторы последовательных вычислений (,), логическое-И (&&), логическое-ИЛИ (||), тернарный (?:) и вызовы функций, гарантируя тем самым конкретный порядок вычисления их операндов. Оператор вызова функции это набор скобок, который следует за идентификатором функции. Оператор последовательных вычислений (,) гарантирует вычисление своих операндов слева направо. (Обратите внимание на то, что запятая, которая разделяет аргументы в вызове функции, не является оператором последовательных вычислений и не дает таких гарантий.) Точки упорядочивания рассматриваются в Разделе 5.2.12. Оператор унарного плюса (+) в определенных ситуациях форсирует группировку. Он реализован синтаксически, но не семантически. Дополнительная информация относительно унарных операторов содержится в Разделе 5.3.2, «Операторы дополнения и унарный плюс». Логические операторы также гарантируют выполнение своих операндов слева направо. Однако, они вычисляют минимальное число операндов, которое необходимо для определения результата выражения. Например, в выражении x&&y++ второй операнд y++ вычисляется только тогда, когда x есть «истина» (не ноль). Т.о. если x есть «ложь» (0), то значение y не увеличивается. В следующем списке показаны группировки по умолчанию для некоторых примеров выражений:

    В первом выражении оператор битового-И (&) имеет приоритет выше, чем оператор логического-ИЛИ (||), поэтому a&b формирует первый операнд операции логического-ИЛИ. Во втором выражении оператор логического-ИЛИ (||) имеет приоритет выше, чем оператор простого присвоения (=), поэтому b||c группируется в качестве правого оператора присвоения. Обратите внимание на то, что a будет присвоено значение 0 или 1. В третьем случае показано корректно сформированное выражение, которое может привести к неожиданному результату. Оператор логического-И (&&) имеет приоритет выше, чем у оператора логического-ИЛИ (||), поэтому q&&r группируется в операнд. Логические операторы гарантируют вычисление своих операндов слева направо, поэтому q&&r будет вычислено раньше, чем s-\,-. Однако, если q&&r даст ненулевое значение, s-\,- не будет вычислено и значение s не уменьшится. Для устранения проблемы следует поставить s-\,- первым операндом выражения или уменьшить значение s в отдельной операции. Следующее выражение некорректно и в процессе компиляции приведет к появлению диагностического сообщения:

    В данном выражении оператор равенства (==) имеет высший приоритет, поэтому p==0 группируется в операнд. Следующий приоритет имеет тернарный оператор (?:). Первый его операнд это p==0, а второй — p+=1. Однако, последним операндом тернарного оператора будет p, а не p+=2, т.к. p относится скорее к тернарному оператору, чем к оператору составного присвоения. Возникает синтаксическая ошибка, т.к. +=2 не имеет левого операнда. Для устранения данной ошибки и улучшения восприятия программы следует воспользоваться скобками, например следующим образом:

    Преобразования типа

    Преобразование типа производится в следующих случаях:

    Если значение одного типа присваивается переменной другого типа.

    Если значение одного типа явно приводится к другому типу.

    Если оператор преобразует тип своего операнда или операндов до выполнения операции.

    Когда значение передается в функцию в качестве аргумента.

    <Преобразования в присвоении >В операциях присвоения тип присваиваемого значение преобразуется в тип переменной, которой делается присвоение. Язык С допускает преобразование типов при присвоении между интегральными типами и типами с плавающей точкой, даже если при преобразовании происходит потеря информации. Используемый метод преобразования зависит от типов, которые участвуют в преобразовании, как это описано в Разделе 5.3.1, «Обычное арифметическое преобразование» и Разделах 5.6.1.1 — 5.6.1.5. Преобразования из интегральных типов со знаком Целая со знаком преобразуется в более короткую целую со знаком путем отбрасывания старших битов и в большую целую со знаком за счет расширения знака. Когда целая со знаком преобразуется в целую без знака, значение целой со знаком преобразуется к размеру целого без знака и результат интерпретируется, как значение без знака. Не происходит потери информации при преобразовании целой со знаком в значение с плавающей точкой. Можно потерять некоторую точность при преобразовании значения long int или unsigned long int в значение float. В Таблице 5.2 приводятся преобразования интегральных типов со знаком. Предполагается, что тип char по умолчанию имеет знак. Если при компилировании используется опция, которая отменяет умолчание и тип char будет без знака, то вместо Таблицы 5.2 нужно пользоваться строкой для unsigned char из Таблицы 5.3.

    В таблице предполагается, что тип char имеет знак. Примечание Тип int эквивалентен типу short или типу long в зависимости от реализации. Преобразование значения int происходит аналогично short или long, соответственно. Преобразования интегральных типов без знака Целое без знака преобразуется в более короткое целое со знаком или без знака отбрасыванием битов старшего порядка или в большее целое со знаком или без знака дополнением нулей. Когда целое без знака преобразуется в целое со знаком того же размера, битовый состав не меняется. Однако представляемое им значение меняется, если бит знака установлен. При преобразовании целого без знака в величину с плавающей точкой оно сначала преобразуется в значение long со знаком, а затем значение long со знаком преобразуется в величину с плавающей точкой. В Таблице 5.3 содержатся преобразования интегральных типов без знака.

    Примечание Тип unsigned int в зависимости от реализации эквивалентен типу unsigned short или unsigned long. Преобразование для unsigned int происходит аналогично unsigned short или unsigned long, соответственно. Преобразования из unsigned long в float, double или long double не обладают достаточной точностью, если преобразуемое значение больше, чем максимальная положительная величина long. Преобразования типов с плавающей точкой Преобразование из типа float в тип double не вносит каких-либо изменений в значение. Преобразование значения из double в float происходит явно, если оно возможно. Может произойти потеря точности, если величина не может быть представлена этим типом. При преобразовании величины с плавающей точкой в интегральное значение она сначала преобразуется в тип long, а затем из типа long в конкретный интегральный тип, как это показано в Таблице 5.4. При преобразовании в long десятичная часть величины с плавающей точкой отбрасывается. Если при этом результат все еще слишком велик, чтобы поместиться в long, то результат преобразования будет неопределен. В Таблице 5.4 приводятся преобразования с плавающей точкой

    Примечание Преобразования из float, double или long double в unsigned long не обеспечивают точности, если преобразуемое значение больше, чем максимальное положительное значение long. Преобразование типов указателей Пойнтер на один тип значения может быть преобразован в указатель на другой тип. Однако, при этом можно получить неопределенный результат из-за требований к выравниванию и размерам различных типов в памяти. Пойнтер типа void может быть преобразован в любой тип и в него может быть преобразован любой тип, без каких-либо ограничений. Преобразования других типов Тип enum по определению имеет значение int, поэтому преобразование из этого типа и в этот тип будет таким же, как и для int. Не допускается преобразование между типами структуры и объединения. Тип void по определению не имеет значения. Т.о. он не может быть преобразован в какой-либо иной тип, и другие типы не могут быть преобразованы в него присвоением. Однако, можно явно привести значение к типу void, как это рассмотрено в разделе 5.6.2. <Приведения типа >Приведение типов можно использовать для их явного преобразования. Приведение типа имеет вид:

    где имя-типа это тип и операнд это значение, которое будет преобразовано в заданный тип. (Имена типов были рассмотрены в Разделе 4.9.) Операнд преобразуется так, как если бы он был присвоен переменной типа имя-типа. Правила преобразования для присвоений (изложенные в Разделе 5.6.1) также применимы и для приведения типов. В операции приведения типа можно использовать можно использовать и имя типа void, но только нельзя присвоить результирующее выражение какому-либо типу. <Преобразования операторов >Преобразования, выполняемые операторами языка С, зависят от оператора и его операнда или операндов. Многие операторы выполняют обычные арифметические преобразования, рассмотренные в Разделе 5.3.1. Язык С выполняет некоторые арифметические действия с указательами. В арифметике указателей целые значения преобразуются для представления ими позиций памяти. (Дополнительная информация содержится в рассмотрении аддитивных операторов в Разделе 5.3.6, и выражений индексов в Разделе 5.2.5.) <Преобразования вызовов функций >Тип преобразований, выполняемых над аргументами в вызове функции, зависит от наличия прототипа функции (ее раннего объявления) с объявленными типами аргументов для вызываемой функции. Если имеется прототип функции, который включает объявленные типы аргументов, то компилятор выполняет проверку типов. Процесс проверки типов детально рассмотрен в Главе «Функции». Если прототипа функции нет или в раннем объявлении старого типа опущен список типов аргументов, то проводятся только обычные арифметические преобразования каждого аргумента в вызове функции. Это означает, что величины float преобразуются в double, char или short в int, unsigned char или unsigned short в unsigned int. Если реализованы специальные ключевые слова near, far и huge, то может быть сделано неявное преобразование значений указателей, передаваемых в функцию. Можно отменить эти неявные преобразования, задав прототип функции и дать тем самым компилятору возможность выполнить проверку типов. Информация о преобразованиях указателей содержится в Вашем Руководстве по компилятору.

    Логический оператор присваивания

    Если в левой части оператора присваивания указана переменная типа boolean, то в правой части оператора должно быть задано логическое выражение, задающее правило вычисления логического значения (true или false).

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

    является отношением, где

    при этом отношение выполняется после всех арифметических операций.

    Отношение имеет значение true, если заданное в нем с помощью операции сравнения соотношение между значениями арифметических выражений действительно имеет место, и значение false — в противном случае. Например, отношение 3 5 — значение false.

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

    Как видно, в логическом выражении из-за наличия в нем отношений могут присутствовать как арифметические, так и логические операции. При этом самой старшей операцией является операция not, применимая к логическому операнду, затем следуют мультипликативные операции (*, /, div, mod, and), потом аддитивные операции (+, —, ог), и самый низкий приоритет имеют операции сравнения (т.е. они выполняются в последнюю очередь). Операции одинакового старшинства выполняются в порядке их следования в выражении слева направо. Для задания любого желаемого порядка выполнения операции, как обычно, используются круглые скобки.

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

    При этом имеется в виду, что здесь , и должны иметь тип boolean.

    Примеры логических выражений (d, b, с — логические, х, у — вещественные, к — целочисленная переменные):

    х у/2) — логический множитель;

    d and (х ф у) and b — логическое слагаемое;

    or d) and (х = у) or not b — простое выражение.

    Еще раз подчеркнем, что в паскале операции отношения считаются самыми младшими, так что если отношение является не самостоятельным выражением, а одним из операндов какой-либо логической операции, то оно должно быть заключено в круглые скобки. Так, если d — логическая переменная, а х, у — вещественные переменные, то запись

    бессмысленна, ибо в силу принятого старшинства операций она будет трактоваться как (d or х) > у, где один из операндов логической операции (or) является вещественным числом. Если нужно, чтобы логическая операция or применялась к значениям переменной d и отношения х > у, то логическое выражение должно быть записано в виде d or (х > у). Впрочем, эта особенность использования отношений отражена и в синтаксическом определении логического выражения.

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

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

    Ранее было принято, что операндами операции отношения являются арифметические выражения, однако это не обязательно. В связи с тем что в паскале упорядочены значения ряда скалярных типов (в том числе значения типа boolean и char), в отношении могут фигурировать выражения любых из этих типов (разумеется, оба выражения должны быть одного и того же типа). Так что если d, Ь, с — логические переменные, a sym — литерная переменная, то на паскале допустимы, например, отношения:

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

    (которое принимает значение true, если точка М(х), лежащая на оси абсцисс, принадлежит отрезку [0, 1], и значение false в противном случае) при отрицательном значении х уже по вычислении первого множителя (значения отношения х > 0) становится ясным значение всего выражения: это значение есть false, так что вычислять второй множитель вообще нет необходимости. Правила вычисления логического выражения в паскале не требуют в таких случаях обязательно вычислять оставшуюся часть выражения, но и не запрещают это делать. Следовательно, при записи и использовании логического выражения программист обязан позаботиться о том, чтобы каждый его операнд имел смысл независимо от значений других операндов во время вычисления значения этого выражения. Игнорирование этого обстоятельства может привести к ошибкам в программе.


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

    Примеры логических операторов присваивания:

    Литерный оператор присваивания

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

    Примеры литерных операторов присваивания (sym, alpha, beta — переменные типа char):

    sym: = ‘ + 1 alpha:=sym beta:=succ(sym)

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

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

    Вычисление арифметического выражения и оператор присваивания

    Для присвоения значения используется оператор присваивания. Синтаксис оператора присваивания:

    [Let] ИмяПеременной = Выражение

    Чаще всего используется арифметическое выражение.

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

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

    • 1) возведение в степень (« Л »);
    • 2) умножение («*») и обычное деление («/»);
    • 3) целочисленное деление («»);
    • 4) вычисление остатка от целочисленного деления (Mod);
    • 5) сложение («+») и вычитание («-»).

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

    Некоторые встроенные математические функции:

    • • Abs (х) — абсолютная величина числа х;
    • • Sqr (х) — квадратный корень из числах;
    • • Fix (х) — целая часть числа х
    • • Int (х) — наибольшее целое число, не превышающее х.

    На рис. 5.5 приведен пример процедуры, вычисляющей арифметическое выражение (площадь круга).

    Рис. 5.5. Пример процедуры вычисления арифметического выражения

    BestProg

    Понятие выражения. Операция присваивания. Преобразование и приведение типов

    Содержание

    1. Что называется выражением в языках программирования?

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

    Примеры выражений.

    2. Какой общий вид операции присваивания? Примеры

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

    В языке C/C++ операция присваивания обозначается символом ‘=’ (равно).

    Общий вид операции присваивания:

    • переменная – имя переменной, которой присваивается значение выражения;
    • выражение – некоторое выражение, которое может быть использовано согласно синтаксису языка C/C++.

    Примеры операции присваивания.

    3. Как используется операция присваивания при инициализации переменных? Примеры

    Общий вид операции присваивания при инициализации переменных:

    • тип – тип переменной, которая инициализируется;
    • выражение_или_значение – значение выражения или константная величина. Если используется значение выражения, то переменные, входящие в это выражение должны быть уже объявлены на данный момент (см. пример).

    Примеры инициализации переменных.

    4. Как осуществляется преобразование типов в выражениях?

    Если в выражении встречаются два операнда разных типов, то действуют следующие правила:

    • все операнды преобразуются к типу самого наибольшего операнда. Процесс такого преобразования называется расширением типа (integral promotion);
    • все типы char и short int преобразуются к типу int . Процесс такого преобразования называется целочисленным расширением (integer promotion);
    • если один из операндов имеет тип double , тогда любой другой операнд приводится к типу double . Даже, в случае с типом char , происходит приведение к типу double ;
    • после преобразования оба операнда имеют одинаковый тип, который есть типом результата операции.

    Ниже приведены примеры автоматического преобразования типов.

    Преобразование между типами char и int :

    Преобразование между типами int и float :

    Преобразование между типами float и double

    5. Как осуществляются преобразования, которые связаны с типом bool ?

    Если выражение содержит целочисленный тип, то значения типа bool автоматически превращаются в целые числа 0 и 1. Значению 0 соответствует значение false . Значению 1 или ненулевому значению соответствует значение true .

    Пример. Фрагмент кода, который демонстрирует преобразование для типа bool

    6. Какой общий вид операции приведения типа?

    Общий вид операции приведения типа:

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

    Примеры использования операции приведения типов.

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

    7. Какие особенности применения круглых скобок и символов «пробел» в выражениях?

    Чтобы улучшить читабельность, в программах используются:


    • символы «пробел»;
    • символы табуляции (клавиши Tab );
    • круглые скобки ( ) . Круглые скобки позволяют также повысить приоритет операций, которые помещены в них. Количество круглых скобок не влияет на скорость вычисления выражения.

    Операция присваивания: =

    В языке Си знак равенства не означает «равно». Он означает операцию присваивания некоторого значения. С помощью оператора

    переменной с именем bmw присваивается значение 2002, т.е. элемент слева от знака = — это имя переменной, а элемент справа — ее значение. Мы называем символ = «операцией присваивания». Еще раз хотим обратить ваше внимание на то, что смысл указанной строки не выражается словами «bmw равно 2002″. Вместо этого нужно говорить так «присвоить переменной bmw значение 2002″. В этой операции действие выполняется справа налево.

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

    С математической точки зрения это бессмыслица. Если вы прибавляете единицу к конечному числу, результат не может быть равен исходному числу. Но как оператор присваивания данная строка имеет вполне определенный смысл, который можно выразить, например, такой длинной фразой «Взять значение переменной с именем i, к нему прибавить 1, а затем присвоить новое значение переменной с именем i«.

    i = i + 1,

    на языке Си не имеет смысла, поскольку 2002 — число. Вы не можете присвоить константе какое-то значение; ее значением является она сама. Поэтому, сидя за клавиатурой, помните, что элемент, стоящий слева от знака =, всегда должен быть именем переменной.

    Тем из вас, кто предпочитает знать правильные названия понятий, скажем, что вместо использованного ранее термина «элемент» обычно употребляют слово «операнд». Операнды — это то, над чем выполняются операции. Например, вы можете описать процесс «поедания» гамбургера как применение операции «поедание» к oпeранду «гамбургер».

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

    /* таблица результатов турнира по гольфу */

    int Jane, tarzan, cheeta, cheeta = tarzan = jane = 68;

    printf(«cheeta tarzan jane «);

    printf(«Cчетпервойпартии%4d %8d %8d «, cheeta, tarzan, jane);

    В то время как многие языки запрещают применять такое троиное присваивание, присутствующее в данной программе, для Си это обычная практика. Присваивания выполняются справа налево сначала переменная jane получает значение 68, затем переменная tarzan и наконец переменная cheeta. Результат выглядит так:

    cheeta tarzan jane

    Счет первой партии 68 68 68

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

    Операторы. Оператор присваивания в Паскаль

    Оператором называется предложение языка программирования, задающее полное описание некоторого, необходимого для исполнения, действия.

    Последовательность операторов представляет собой основную часть программы на языке Паскаль. Разделителем операторов в программе является символ «точка с запятой».

    Оператор присваивания

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

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

    Рассмотрим работу оператора присваивания в данном примере пошагово:

    1. Из ячейки памяти с именем k выбирается текущее значение.
    2. К текущему значению прибавляется 10.
    3. Результат записывается в ту же самую ячейку памяти (предыдущее значение восстановить после новой записи невозможно!)

    ВНИМАНИЕ: выражение должно быть совместимо по типу данных с переменной.

    В PascalABC.NET определены также операторы присваивания со значками +=, -=, *=, /= . Действие этих операторов заключается в изменении значения переменной в правой части оператора с учетом обозначенной арифметической операции (перед знаком равенства) и значения в правой части. Например:

    • k += 100;
    • n -= 8;
    • m *= 10;
    • b /= 2;

    Copyright © 2014-2020, Урок информатики
    Все права защищены

    Оператор присваивания. Запись значения в переменную на Си

    Пожалуйста, приостановите работу AdBlock на этом сайте.

    Как Вы помните, переменные нужны чтобы хранить в них какие-то данные. Разберёмся как использовать переменные по их прямому назначению. Основной вопрос такой: «Как сохранить значение в переменной». Или вспоминая аналогию с коробкой «Как положить что-то в коробку?»

    Ответ прост. Для этого существует специальный оператор, который называется оператором присваивания и обозначается символом равно «=». Обычно говорят не сохранить значение в переменную, а присвоить переменной значение.

    Как работает оператор присваивания?

    Сразу будем разбираться на примерах.

    Листинг 1. Присваивание значения переменной

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

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

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

    Есть несколько важных моментов на которых надо отдельно заострить внимание:

    • в некоторых языках программирования, после того как вы создали переменную, в ней сразу же хранится значение нуль. В языке Си это не так. Пока переменной не присвоено какое-нибудь значение, в ней будет храниться «мусор». Как этот мусор выглядит мы посмотрим на следующем уроке.
    • справа от знака равно НЕ обязательно должно быть записано какое-то конкретное число, там может быть записано арифметическое выражение или имя переменной.

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

    Если справа от знака равно записано выражение, то сначала вычисляется его значение и уже оно сохраняется в переменную, которая записана слева от =.

    Когда переменной присваивается значение, то то, что хранилось в ней до этого удаляется.

    Обратите внимание, новое значение не добавляется к старому, а полностью заменяет его. Я как-то говорил, что переменные похожи на коробки, но только на первый взгляд. Теперь мы видим, что наша аналогия с коробкой не совсем точная. Если бы в коробке лежало десять шариков, и мы бы туда положили ещё пять, то их стало бы 15.

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

    При вычислении выражения n — 3, n равняется 5. Это потому, что исходное значение 10, заданное при инициализации, мы в программе изменяли. А при вычислениях используется текущее значение переменной.

    В выражении справа от знака равенства может быть использована сама переменная.

    Кажется, что это какой-то порочный круг, но на самом деле проблем здесь не возникнет. Т.к. сначала вычисляется выражение справа, а только потом происходит присваивание. По аналогии с предыдущим примером при вычислении значения справа от знака равно вместо переменной n будет подставлено её текущее значение, т.е. 10. Потом будет произведено сложение и присваивание.


    Ещё один поучительный пример.

    Если Вы подумали что 5, то это неправильно. Никто не знает, что в ней будет записано. Т.к. неизвестно, что было записано в переменной z. Ещё раз напоминаю, что если переменной не присвоено никакое значение, в ней хранится не нуль, а неизвестно что.

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

    Теперь ещё один важный момент, который надо понимать. Когда я рассказывал о типах данных, я говорил, что в переменной можно хранить значения только того же типа, что и тип переменной. Например, в переменную целого типа нельзя положить вещественное число. Этот принцип применяется и с выражениями. Чтобы программа работала корректно, необходимо, чтобы тип выражения или переменной справа от знака присваивания совпадал с типом переменной.

    Посмотрим несколько примеров.

    Внимание на последнюю строчку! Хотя справа выражение целого типа, а слева вещественная переменная, данная команда всё равно будет работать так, как надо. Это из-за того, что все целые числа можно записать как вещественные, у которых дробная часть равна нулю. Подобная штука называется неявное приведение (преобразование) типов . С этой возможностью надо быть очень осторожным, т.к. компилятор не отслеживает такие ошибки. Другими словами программа будет скомпилирована, но работать будет неправильно. Мы ещё вернёмся к этому в следующем уроке, когда научимся выводить значение переменных на экран компьютера.

    Практика

    Решите предложенные задачи. Для удобства работы сразу переходите в полноэкранный режим

    Выражения и приведение арифметических типов

    Читайте также:

    1. I. Вставьте одно или несколько недостающих слов в выражениях.
    2. А. Методики опознания эмоционального выражения лиц на фотографиях
    3. Абдулатипов Рамазан Гаджимурадович
    4. Алгоритм нормализации (приведение к 3НФ)
    5. Алгоритм рішення типових задач по темі
    6. Алгоритм рішення типових задач по темі
    7. Алгоритм рішення типових задач по темі
    8. Алгоритм рішення типових задач по темі
    9. Алгоритм рішення типових задач по темі
    10. Алгоритм рішення типових задач по темі
    11. Алгоритм рішення типових задач по темі
    12. Алгоритм рішення типових задач по темі

    Разделители

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    float absx (float x)

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

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

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

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

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

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

    for (x=pl,y=p2,i=2; i

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

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

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

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

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

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

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

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

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

    int F = 66;

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

    #include

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

    В арифметических выражениях допустимы следующие операции:

    % — деление по модулю (т.е. получение остатка от целочисленного деления первого операнда на второй).

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

    Примеры выражений с двумя операндами:

    а+b 12.3-х 3.14159*Z k/3 16%i

    Нужно быть аккуратным, применяя операцию деления ‘/’ к целочисленным операндам. Например, как мы уже упоминали выше, за счет округления результата значением выражения 5/3 будет 1, а соответствует ли это замыслам программиста, зависит от смысла той конкретной конструкции, в которой это выражение используется. Чтобы результат выполнения арифметической операции был вещественным, необходимо, чтобы вещественным был хотя один из операндов. Например, значением выражения 5.0/2 будет 2.5, что соответствует смыслу обычного деления.

    Операции *, /, % имеют один ранг (3), операции +, — также один ранг (4), но более низкий. Арифметические операции одного ранга выполняются слева направо. Для изменения порядка выполнения операций обычным образом используются скобки. Например, выражение (d+b)/2.0 позволяет получить среднее арифметическое операндов d и b.

    Введены специфические унарные операции ++ (инкремент) и — (декремент) для изменения на 1 операнда, который в простейшем случае должен быть переменной (леводопустимым значением). Каждая из этих операций может быть префиксной и постфиксной:

    • выражение ++m увеличивает на 1 значение m, и это полученное значение используется как значение выражения ++m (префиксная форма);

    • выражение —к уменьшает на 1 значение к, и это новое значение используется как значение выражения —к (префиксная форма);

    • выражение i++ (постфиксная форма) увеличивает на 1 значение i, однако значением выражения i++ является предыдущее значение i (до его увеличения);


    • выражение j— (постфиксная форма) уменьшает на 1 значение j, однако значением выражения j— является предыдущее значение j (до его уменьшения).

    Например, если n равно 4, то при вычислении выражения n++*2 результат равен 8, а n примет значение 5. При n, равном 4, значением выражения ++n*2 будет 10, а n станет равно 5.

    Операнд для операции ++ (и для операции — -) не может быть константой либо произвольным выражением. Записи ++5 или 84++ будут неверными. ++(j+k) также неверная запись.

    Внешнюю неоднозначность имеют выражения, в которых знак унарной операции ++ (или —) записан непосредственно рядом со знаком бинарной операции +:

    В этих случаях трактовка выражений однозначна и полностью определяется рангами операций (бинарные аддитивные + и — имеют ранг 4; унарные ++ и — имеют ранг 2). Таким образом:

    х+++b эквивалентно (х++)+b

    z—d эквивалентно (z—)-d

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

    = больше или равно;

    a-b>6.3

    (x-4)*3==12

    б , >=, с && а+с>b && b+с>а

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

    Так как значением отношения является целое (0 или 1), то ничто не противоречит применению логических операций к целочисленным значениям. При этом принято, что любое ненулевое положительное значение воспринимается как истинное, а ложной считается только величина, равная нулю. Значением !5 будет 0, значением 4 && 2 будет 1 и т.д.

    Присваивание (выражение и оператор). Символ «=» в языке Си обозначает бинарную операцию, у которой в выражении должно быть два операнда — левый (обычно переменная) и правый (обычно выражение). Если z — имя переменной, то

    есть выражение со значением 7.4. Одновременно это значение присваивается и переменной z. Только в том случае, когда в конце выражения с операцией присваивания помещен символ «;», это выражение становится оператором присваивания. Таким образом,

    есть оператор простого присваивания переменной z значения, равного 7.4.

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

    Так как выражение справа от знака ‘=’ может содержать, в свою очередь, операцию присваивания, то в одном операторе присваивания можно присвоить значения нескольким переменным, т.е. организовать «множественное» присваивание, например:

    Здесь значение 6.4 присваивается переменной d, затем 6.4 как значение выражения с операцией присваивания «d=4.0+2.4» присваивается х и, наконец, 6.4 как значение выражения «x=d» присваивается с. Естественное ограничение — слева от знака ‘=’ в каждой из операций присваивания может быть только леводопустимое выражение (имя переменной).

    В языке Си существует целый набор «составных операций присваивания» <ранг 14). Каждая из составных операций присваивания объединяет некоторую бинарную логическую или арифметическую операцию и собственно присваивание. Операция составного присваивания является основой оператора составного присваивания:

    имя переменной ор=выражение;

    где ор — одна из операций *, /, %, +, -, &, Ù , |, «, ». Если рассматривать конструкцию «ор=» как две операции, то вначале выполняется ор, а затем ‘=’. Например,

    х*=2; z+=4; i/=x+4*z;

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

    Таким образом, первый пример можно рассматривать как обозначение требования «удвоить значение переменной х»; второй пример — «увеличить на 4 значение переменной z»; третий пример — «уменьшить значение переменной i в (x+4*z) раз». Этим операторам эквивалентны такие операторы простого присваивания:

    х=х*2; z=z+4; i=i/(x+4*z) ;

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

    Приведение типов.Рассматривая операцию деления, мы отметили, что при делении двух целых операндов результат получается целым. Например, значением выражения 5/2 будет 2, а не 2.5. Для получения вещественного результата нужно выполнять деление не целых, а вещественных операндов, например, записав 5.0/2.0, получим значение 2.5.

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

    d=(double) n/ (double) k;

    В этом фрагменте значением d станет величина 2.5 типа double, а значением переменной m станет целое значение 2.

    Операция деления является только одной из бинарных операций. Почти для каждой из них операнды могут иметь разные типы. Однако не всегда программист должен в явном виде указывать преобразования типов. Если у бинарной операции операнды имеют разные типы (а должны в соответствии с синтаксисом выражения иметь один тип), то компилятор выполняет преобразование типов автоматически, т.е. приводит оба операнда к одному типу. Например, для тех же переменных значение выражения d+k будет иметь тип double за счет неявного преобразования, выполняемого автоматически без указания программиста. Рассмотрим правила, по которым такие приведения выполняются.

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

    Правила преобразования в языке Си для основных типов определены стандартом языка. Эти стандартные преобразования включают перевод «низших» типов в «высшие».

    Среди преобразований типов выделяют:

    • преобразования в арифметических выражениях;

    • преобразования при присваиваниях;

    Преобразование типов указателей будет рассмотрено в позже. Здесь рассмотрим преобразования типов при арифметических операциях и особенности преобразований типов при присваиваниях.

    При преобразовании типов нужно различать преобразования, изменяющие внутреннее представление данных, и преобразования, изменяющие только интерпретацию внутреннего представления. Например, когда данные типа unsigned intпереводятся в тип int,менять их внутреннее представление не требуется — изменяется только интерпретация. При преобразовании значений типа float в значение типа int недостаточно изменить только интерпретацию, необходимо изменить длину участка памяти для внутреннего представления и кодировку. При таком преобразовании из float в int возможен выход за диапазон допустимых значений типа int, и реакция на эту ситуацию существенно зависит от конкретной реализации. Именно поэтому для сохранения мобильности программ в них рекомендуется с осторожностью применять преобразование типов.

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

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

    2. Если один из операндов имеет тип long double, то второй тоже будет преобразован в long double.

    3. Если п. 2 не выполняется и один из операндов есть double, другой приводится к типу double.

    4. Если п. 2 — 3 не выполняются и один из операндов имеет тип float, то второй приводится к типу float.

    5. Если п. 2 — 4 не выполняются (оба операнда целые) и один операнд unsigned long int, то оба операнда преобразуются к типу unsigned long int.

    6. Если п. 2 — 5 не выполняются и один операнд есть long, другой преобразуется к типу long.

    7. Если п. 2 — 6 не выполняются и один операнд unsigned, то другой преобразуется к типу unsigned.

    8. Если п. 2 — 7 не выполнены, то оба операнда принадлежат типу int.

    Используя арифметические выражения, следует учитывать приведенные правила и не попадать в «ловушки» преобразования типов, так как некоторые из них приводят к потерям информации, а другие изменяют интерпретацию битового (внутреннего) представления данных.

    Дата добавления: 2014-12-16 ; Просмотров: 568 ; Нарушение авторских прав? ;

    Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет

    Оператор присваивания

    Оператор присваивания

    К огда мы работаем с переменными, необходимо изменять их значение. Это делается с помощью оператора присваивания =

    Оператор присваивания имеет особенность — он возвращает правое значение. Это значит, что можно использовать несколько операторов присваивания подряд, по цепочке.

    В этом примере переменной c присваивается значение 10, после чего оператор присваивания возвращает значение 10, которое используется следующим оператором, и присваивает значение 10 переменной b, после чего возвращает значение 10, которое используется следующим оператором. Это свойство — возвращать значение — часто используется. Например, при выделении памяти мы можем узнать, была ли действительно выделена память.

    Здесь одновременно выделяется память и проверяется, что было возвращено при попытке получить память. Этот же пример может быть записан и так

    (вам этот пример кажется непонятным, здесь важно для вас только использование оператора =).

    rvalue и lvalue

    Л юбая переменная связана с адресом в памяти и хранит некоторое значение. Выражение типа

    говорит о том, что мы заносим в область памяти, на которую указывает переменная i значение 20. Выражение
    20 += 3;
    не имеет смысла, поскольку 20 — это литерал, значение, которое не связано с областью памяти.
    Для обозначения объектов, которым может быть присвоено значение, используется понятие lvalue (буквально, то, что может стоять слева от оператора присваивания). Для обозначения объектов, которые имеют только значения, используют выражение rvalue (то, что стоит справа от оператора присваивания). lvalues в свою очередь делят на modifiable lvalues, которые могут быть изменены, и non-modifiable lvalues, которые связаны с областью памяти, но не могут быть изменены, например, константы. В том случае, если lvalue стоит справа от оператора присваивания, например

    то происходит lvalue-to-rvalue convertion, преобразование lvalue к rvalue.
    К rvalue относятся результаты арифметических выражений, преобразование не к ссылочным типам, результат постфиксных операций ++ и —, литералы за исключением строк.
    К lvalue относятся переменные, выражения ссылочных типов, результат операции разыменования *, строковые литералы, результат префиксных операций ++ и — над ссылочными типами.
    Имена функций и массивов, также объявленные как немодифицируемые объекты, являются non-modifiable lvalues.

    Илон Маск рекомендует:  Программистом быть классно!
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL