Операторы условных и безусловных переходов. — Информатика, информационные технологии
Операторы циклов.
Операторы цикла используются для организации многократно повторяющихся вычислений. Любой цикл состоит из тела цикла, то есть тех операторов, которые выполняются несколько раз, начальных установок, модификации параметра цикла и проверки условия продолжения выполнения цикла.
Для удобства, а не по необходимости, в C++ есть три разных оператора цикла — while, do while и for.
1) Цикл с предусловием имеет вид: while (выражение) оператор.
Рис.1 Структурная схема цикла с предусловием
Выражение определяет условие повторения тела цикла, представленного простым или составным оператором. Выполнение оператора начинается с вычисления выражения. Если оно истинно (не равно false), выполняется оператор цикла. Если при первой проверке выражение равно false, цикл не выполнится ни разу.
Пример (программа находит все делители целого положительного числа):
2) Цикл с постусловием имеет вид: do оператор while (выражение).
Рис.2 Структурная схема цикла с постусловием
Сначала выполняется простой или составной оператор, составляющий тело цикла, а затем вычисляется выражение. Если оно истинно (не равно fаlse), тело цикла выполняется еще раз. Цикл завершается, когда выражение станет равным false или в теле цикла будет выполнен какой-либо оператор передачи управления.
Пример (программа осуществляет проверку ввода):
3) Цикл с параметром.
Цикл с параметром имеет следующий формат: for (инициализация: выражение: модификации) оператор. Инициализация используется для объявления и присвоения начальных значений величинам, используемым в цикле. В этой части можно записать несколько операторов, разделенных запятой (операцией «последовательное выполнение»).
Пример (оператор, вычисляющий сумму чисел от 1 до 100):
Областью действия переменных, объявленных в части инициализации цикла, является цикл. Инициализация выполняется один раз в начале исполнения цикла. Выражение определяет условие выполнения цикла. Модификации выполняются после каждой итерации цикла и служат обычно для изменения параметров цикла.
Операторы условных и безусловных переходов.
1) Условный оператор if
Данный оператор используется для разветвления процесса вычислений на два направления. Структурная схема оператора приведена на рис. 3. Формат оператора: if (выражение) оператор_1; [else оператор_2;].
Оператор if позволяет определить действие при истинном условии, т.е. если логическое_выражение имеет значение true, выполняется составной_оператор_1, а если логическое_выражение имеет значение false, то управление передается следующему оператору после оператора if.
Рис.3 Структурная схема оператора if
Пример:
2) Условный оператор двойного выбора if…else
Оператор if…else применяется для того чтобы в зависимости от конкретных значений исходных данных обеспечить выполнение двух разных составных операторов. Структурная схема оператора приведена на рис. 4. Формат оператора: if (логическое_выражение) {составной_оператор_1;} else {составной_оператор_2; }.
Рис.4 Структурная схема оператора if…else
Оператор if else позволяет определить программисту действие, когда условие истинно и альтернативное действие, когда условие ложно, т.е. если логическое_выражение имеет значение true, то выполняется составной_оператор_1, а если логическое_выражение имеет значение false, то выполняется составной_оператор_2. Так как логическое_выражение не может одновременно иметь значения true и false, то составной_оператор_1 и составной_оператор_2 не могут выполняться оба. После выполнения составной_оператор_1 или составной_оператор_2 управление передается следующему оператору после оператора if.
Пример:
3) Оператор безусловного перехода
Оператор goto имеет формат: goto метка. В теле той же функции должна присутствовать ровно одна конструкция вида: метка: оператор.
Оператор goto передает управление на помеченный оператор. Метка — это обычный идентификатор, областью видимости которого является функция, в теле которой он задан.
Использование оператора безусловного перехода оправдано в двух случаях, если принудительный выход вниз по тексту программы из нескольких вложенных циклов или переключателей или переход из нескольких мест функции в одно (например, если перед выходом из функции всегда необходимо выполнять какие-либо действия).
В остальных случаях для записи любого алгоритма существуют более подходящие средства, а использование goto приводит только к усложнению структуры программы и затруднению отладки. Применение goto нарушает принципы структурного и модульного программирования, по которым все блоки, из которых состоит программа, должны иметь только один вход и один выход. В любом случае не следует передавать управление внутрь операторов if, switch и циклов. Нельзя переходить внутрь блоков, содержащих инициализацию переменных, на операторы, расположенные после нее, поскольку в этом случае инициализация не будет выполнена.
Пример:
Оператор выбора.
Структура множественного выбора (switch) применяется для того чтобы в зависимости от конкретных значений исходных данных обеспечить выполнение множества разных составных операторов. Структурная схема оператора приведена на рис. 3. Формат оператора:
Рис.3 Структурная схема оператора выбора
Оператор switch позволяет определить программисту действие из списка возможных вариантов, т.е. если значение выражения совпадает со значением константное_выражение_1, то выполняется составной оператор_1, если со значением константное_выражение_2, то выполняется составной оператор_2 и т.д. Если совпадения не произошло, выполняется составной_оператор_по_умолчанию, расположенный после слова default. Выполнение не может переходить на следующий раздел switch.
Пример (программа реализует простейший калькулятор на 4 действия):
Оператор switch может содержать любое количество разделов switch, а каждый раздел может иметь одну или несколько меток case. Однако две метки case не могут содержать одно и то же постоянное значение. Выполнение списка операторов в выбранном разделе switch начинается с первого оператора и продолжается по списку, обычно до достижения оператора перехода, такого как break, goto case, return или throw (оператор break выполняет выход из самого внутреннего из объемлющих его операторов switch; оператор goto выполняет переход на указанную после него метку, обычно это метка case одной из нижележащих ветвей оператора switch ; оператор return выполняет выход из функции, в теле которой он записан). В этой точке управление передаётся за пределы оператора switch или к другой метке case. Не допускается, чтобы выполнение, начавшись в одном разделе, продолжалось в следующем.
Статьи к прочтению:
- Операторы вывода write/writeln
- Операторы ввода read/readln
Assembler — операторы условия
Похожие статьи:
Оператор условного перехода
Оператор условного перехода предназначен для выбора одного из двух операторов в зависимости от значения некоторого проверяемого условия. условие оператор…
Указания к выполнению задания. условный оператор if / then / else
Условный оператор IF / THEN / ELSE Различают однострочные и многострочные конструкции оператора If. Однострочный оператор if/then IfThen При выполнении…
Оператор goto: что это, зачем необходимо и где применяется
Оператор goto применяется в основном в прикладном или системном программировании на высокоуровневых языках, которые поддерживают разбивку кода на структуру и структурную обработку исключений:
- Java;
- C#;
- C++;
- C;
- Python;
- и др.
Это довольно спорный оператор, и по сей день ведется много дискуссий по поводу необходимости его применять. Так происходит, потому что мотивы его применения при разном подходе программирования очень сильно отличаются.
Оператор goto нужен в тех случаях, когда по каким-то причинам необходимо осуществить безусловный переход к определенной точке в коде программы, как правило, эта точка обозначается номером строки или меткой. Поэтому в основном этот оператор состоит из 2-х частей:
- Самого оператора goto;
- Метки. В основном метка goto — это какое какое-то число, но в некоторых языках это может быть абсолютно любой идентификатор.
Основная цель этого оператора заключается в том, что он определяет порядок исполнения программы. То есть программа будет исполняться сразу после метки goto.
Можно постараться обобщить свойства goto:
- Вообще не структурирован. То есть он может применяться в абсолютно любом месте кода, место его применения ни от чего не зависит.
- Может сгруппировать исходный код. Если есть структура кода, то в принципе можно оперировать блоками кода по-разному: переставлять их местами, как в конструкторе ЛЕГО. Однако если применить оператор goto, то «конструктор» с блоками будет практически невозможен, потому что это способно напрочь сломать программу.
Применениеgoto в коде программы в первую очередь влияет на качество самого кода и на его компоненты.
Поэтому применение goto должно быть хорошо обдуманным, а возможно, даже проще найти какие-нибудь более безопасные альтернативы.Оператор goto в современном программировании — часто в более «древних» языках, таких как Basic или Fortan, реже он используется в Си. В более современных языках его стараются не использовать, потому что существуют альтернативные и более эффективные методы:
- использование циклов;
- внедрение обработчиков исключений;
- деструкторы;
- и др.
Раньше оператор goto активно применяли, особенно в Си. Но современное программирование очень усложнилось, и его применение стало нецелесообразно. Многие современные программисты замечают, что применение goto дает неконтролируемую возможность «прыгать по коду». А когда код разрастается, то получается эффект «spaghetti». «Spaghetti-код» — это код, который очень сильно запутан и закручен, что напоминает одноименное блюдо.
Поэтому есть общая рекомендация по применению этого оператора:
Применять оператор goto можно только при условии, когда на это есть очень веская причина, а поиск альтернативных методов не принес никаких результатов.
Схожие статьи
Другое
Современные методы разработки программного обеспечения для ПК
Другое
Транспонирование таблицы SQL: какой запрос может в этом помочь
Другое
Программа распознавания лиц: специфика технологии, сервисы и примеры
Другое
Электронный ридер PocketBook Pro 602: характеристики и инструкция
Безусловные переходы и условные переходы — IC 123
Справочные статьи:
В RV32I существует два основных типа инструкций по передаче управления: безусловные переходы и условные переходы.
Инструкции безусловного перехода используют адресацию относительно ПК. Безусловный переход в основном включает две инструкции: JAL и JALR.
2.1 JAL
Инструкции JAL имеют формат J-типа (JAL — единственная инструкция J-типа в RV32I).
Формат инструкций JAL: JAL rd, offset . х[rd] = пк+4; pc += sext(offset)
Формат машинного кода показан на рис. 1. Его код операции 110_1111. Эта инструкция сохраняет адрес следующей инструкции (PC + 4) в регистре rd, а затем устанавливает PC равным текущему значению плюс дополненное знаком смещение.
Рис. 1 Формат машинного кодирования JAL [1]
Обратите внимание, что смещение расширено знаком. Видно, что смещение выровнено по 2 байтам (смещение [20:1]), хотя все адреса инструкций в RV32I выровнены по 4 байтам, но JAL также может использоваться для совместимости с расширенным набором инструкций C (подробности см. Введение в RISC-V (4) Структура кодирования набора инструкций RISC-V для его описания), поэтому бит смещения 0 по умолчанию равен 0 (т. е. выравнивание по 2 байтам). 921 = 2 МБ = +/- 1 МБ).
Стандартное соглашение о вызовах программного обеспечения (соглашение о вызовах) использует регистр x1 в качестве регистра обратного адреса (rd), также можно использовать x5 в качестве альтернативного регистра ссылки (регистр связи).
В JAL rd метка в метке — это метка, которая используется для обозначения местоположения определенной программы и обеспечивает запись перехода для операторов перехода и ветвления в программе (пример использования метки можно щелкнуть здесь ). Компилятор автоматически вычислит метку и смещение текущей инструкции.
Пример:
JAL x1, main
Псевдоинструкция: JAL main, соответствующая реальная инструкция: JAL x1, main
Псевдоинструкция: J main, соответствующая реальная инструкция: JAL x0, main
Перейти к основной функции и сохранить следующую инструкцию в регистре x1
Примечание:
- 90 033 Был выбран регистр x5 в качестве альтернативной ссылки зарегистрируйтесь по двум причинам:
- используется как временная переменная в стандартном соглашении о вызовах
- Отличается от обычного компоновщика всего на 1 бит x1 0_0001 -> 0_0101
- Если в инструкции JAL отсутствует rd, по умолчанию rd равен x1. 12 = 4096 = 4 КБ = +/- 2 КБ). Инструкция JALR определена таким образом, что две последовательности инструкций могут переходить в любое место в пределах 32-битного диапазона абсолютных адресов (поскольку диапазон перехода инструкции JAL недостаточно велик).
Пример:
JALR x13, 0(x1)
Перейти к адресу, хранящемуся в регистре x1, и сохранить следующую инструкцию в регистре x13.
Примеры других псевдокоманд:
JR x1 => JALR x0, x1, 0
RET => JALR x0, x1, 0
JALR x13 => JALR x1, x13, 0
Вообще говоря, комбинация LUI и JALR может перейти к 32-битному диапазону абсолютных адресов, а комбинация AUIPC и JALR может перейти к 32-битному диапазону адресов. относительно ПК.
. 12:1]) кратными 2 байтам. 913 = 8192 = 8 КБ = +/- 4 КБ.
Как и в JAL, при обычном использовании инструкции перехода можно также заменить смещение меткой, такой как BEQ rs1, rs2, метка .
Рис. 3. Формат машинного кодирования команд ветвления [1]
3.
1 BEQBEQ (ветвь при равенстве, ветвь при равенстве), его формат инструкции BEQ rs1, rs2, offset . if (rs1 == rs2) pc += sext(offset)
Как показано на рисунке 4, его код операции — 110_0011, а funct3 — 000. Эта инструкция предназначена для определения того, равны ли значения в регистре rs1 и регистре rs2. Если они равны, установите значение PC равным текущему значению плюс смещение смещения расширения знакового бита.
Пример:
BEQ x12, x13, LOOP
Сравнить значения в регистрах x12 и x13 на равенство , и если да, то перейти к LOOP(метка).
Рисунок 4 Формат машинного кодирования BEQ [2]
3.2 BNE
BNE (ветвь, если не равно, ветвь, если не равно), его формат инструкции: BNE rs1, rs2, смещение. if (rs1 ≠ rs2) pc += sext(offset)
Как показано на рисунке 5, его код операции — 110_0011, а funct3 — 001. Эта инструкция предназначена для определения того, не равны ли значения в регистре rs1 и регистре rs2. Если они не равны, установите значение PC равным текущему значению плюс смещение смещения расширения знакового бита.
Пример:
BNE x12, x13, LOOP
Сравнить значения в регистрах x12 и x13 на равенство, если не , перейти к LOOP(метка).
. if (rs1
Как показано на рисунке 6, его код операции — 110_0011, а funct3 — 100. Эта инструкция определяет, меньше ли значение регистра rs1 значения в регистре rs1. rs2 (все считается числом со знаком), и если это так, установите значение PC равным текущему значению плюс смещение знакового бита расширения.
Пример:
BLT x12, x13, LOOP
Signed сравнивает значения в регистрах x12 и x13, если значение в регистре x12 на меньше x13, скачок в LOOP(метка ).
. если (rs1
Как показано на рисунке 7, его код операции — 110_0011, а funct3 — 110. Эта инструкция предназначена для определения того, меньше ли значение регистра rs1 значения в регистре rs2 (все рассматриваются как числа без знака), если да, установить значение ПК к текущему значению плюс смещение расширения знакового бита.
Пример:
BLTU x12, x13, LOOP
Unsigned сравнивает значения в регистрах x12 и x13, если значение в регистре x12 равно меньше x13, перейти к LOOP(метка).
. if (rs1 ≥s rs2) pc += sext(offset)
Как показано на рисунке 8, его код операции — 110_0011, а funct3 — 101. Эта инструкция определяет, больше или равно ли значение регистра rs1 значению в регистре rs2 (все считаются числами со знаком), если да, то установить значение ПК равным текущему значению плюс смещение регистра расширение знакового бита.
Пример:
BGE x12, x13, LOOP
Signed сравнивает значения в регистрах x12 и x13, если значение в регистре x12 на больше или равно x1 3, перейти к ПЕТЛЯ (этикетка).
Рисунок 8 Формат машинного кодирования BGE [2]
3.6 BGEU
BGEU (ветвь, если больше или равно, без знака, ветвь, если больше или равно), формат инструкции BGEU rs1, rs2, смещение . если (rs1 ≥u rs2) pc += sext(offset)
Как показано на рис. 9, ее код операции — 110_0011, а funct3 — 111. Эта инструкция определяет, больше или равно ли значение регистра rs1 значению в регистре rs2 (все рассматриваются как числа без знака), если поэтому установите значение PC равным текущему значению плюс смещение расширения знакового бита.
Пример:
BGEU x12, x13, LOOP
Unsigned сравнивает значения в регистрах x12 и x13, если значение в регистре x12 равно больше или равно x13, перейти к LOOP (метка).
. Доступно: https://riscv.org/wp-content/uploads/2019/12/riscv-spec-20191213.pdf. [Доступ: 22 февраля 2021 г.].
[2] Д. Паттерсон и А. Уотерман, Читатель RISC-V . Беркли: Strawberry Canyon LLC, 2018.
Теговый условный переход, инструкция перехода, RISC-V, безусловный переход, безусловные переходы и условные переходы 9Сборка 0003
— В чем разница между безусловным переходом и безусловным переходом (инструкции в MIPS)?
Переход и безусловный переход в MIPS — это не одно и то же.
Как инструкции ветвления, так и инструкции перехода записывают данные в регистр счетчика программ, так что при следующем цикле выборки вместо следующей инструкции в строке памяти программ будет выбрана другая инструкция. В этом смысле они выполняют один и тот же тип операции.
Отличие заключается в том, что переходы являются условными, они изменяют следующую команду для выполнения только в том случае, если выполняется определенное условие. Это можно проиллюстрировать разницей в коде выполнения в
, если оператор
или вызов функции.если (а == 0) { а = 1 } установитьAtoOne()
Оператор
if
переходит к инструкции установкиa = 1
только в том случае, еслиa == 0
. Функция перейдет к этой инструкции в любом случае.В данном случае мы говорим о ветке, где условие всегда истинно. Это просто другой способ записи
beq $zero, $zero, (int)offset
$zero всегда равен $zero, поэтому он всегда переходит к указанному смещению. Это похоже на это, если утверждение
если (истинно) { а = 1 }
Есть еще одно различие между инструкциями ветвления и перехода. Инструкции перехода указывают абсолютный адрес, на который будет установлен ПК, тогда как инструкции ветвления смещают адрес в программном счетчике.
ПК = 32-битный адрес # Перейти ПК += 16 бит ниже
На самом деле это не совсем так. Мы пишем сборку с абсолютными адресами и смещениями, но и в прыжках, и в ответвлениях она компилируется со смещением. Вот почему вы не можете прыгать или переходить куда-либо в памяти, ожидайте использования прыжка для регистрации
jr
инструкция. Это связано с фундаментальной конструкцией MIPS, однословными инструкциями фиксированной длины.Все инструкции MIPS имеют длину 1 слово (т.е. 4 байта/32 бита). Они содержат идентификатор инструкции (называемый операционным кодом), который составляет 6 бит, а также другую информацию, необходимую для выполнения инструкции. Это может быть идентификатор регистров или «непосредственные» значения, в основном целые числа, закодированные в инструкции.
Каждый байт в памяти в MIPS имеет адрес между
0x00000000
—0xFFFFFFFF
. Чтобы добраться до одного из этих байтов, нам нужно указать адрес. Если бы повезло сохранить адрес в регистре, мы бы простоjr
и использовали адрес, уже сохраненный в регистре. Однако это не так.Это становится проблематичным, у нас есть только 32 бита для наших инструкций, и нам понадобятся все эти биты, чтобы указать адрес в этом диапазоне. Нам также пришлось отказаться от 6 бит, которые процессор использовал для идентификации инструкции. Теперь у нас осталось 26 бит.
Что еще хуже, когда мы переходим, нам нужно 10 дополнительных битов, чтобы указать два регистра, которые мы сравниваем для нашего условия.
Допустим, мы находимся по адресу
0x12345678
и выполняем безусловный переход на следующий адрес в памятиj 0x1234567c
. Это ассемблерный код, и я покажу, как он транслируется в машинный код и выполняется.Сначала немного схитрим. Мы знаем, что инструкции состоят из одного слова (4 байта), а в MIPS указано, что они должны находиться в пределах границ слова. Это означает, что все инструкции имеют адреса, разделенные 4 байтами, и это означает, что они всегда заканчиваются на 00 в двоичном представлении. Отлично, мы можем сбрить эти два бессмысленных кусочка. Мы также бреем первые 6, но не волнуйтесь, мы вернем их позже.
Когда мы выполняем это, мы беремпрыжок 0001 0010 0011 0100 0101 0110 0111 11
00прыжок00010010 0011 0100 0101 0110 0111 11000000 10 00 1000 1101 0001 0101 1001 1111 #in машинный код # jump op = 0000 10
Затем мы И ПК (с которого мы выполняем) и 0xf000000000 1000 1101 0001 0101 1001 1111 0000 00 00 1000 1101 0001 0101 1001 1111 # продлить >> 6 0000 00 10 0011 0100 0101 0110 0111 11 00 # << 2
0001 0010 0011 0100 0101 0110 0111 1000 1111 0000 0000 0000 0000 0000 0000 0000 И 0001 0000 0000 0000 0000 0000 0000 0000
Мы знаем, что нужно взять результат этого и выполнить операцию ИЛИ с целочисленной командой
0001 0000 0000 0000 0000 0000 0000 0000 0000 0010 0011 0100 0101 0110 0111 1100 ИЛИ 0001 0010 0011 0100 0101 0110 0111 1100
Что такое
0x1234567c
в Hex и куда мы хотим попасть, теперь туда и прыгаем.