- ВКонтакте
- РћРТвЂВВВВВВВВнокласснРСвЂВВВВВВВВРєРСвЂВВВВВВВВ
- РњРѕР№ Р В Р’В Р РЋРЎв„ўР В Р’В Р РЋРІР‚ВВВВВВВВРЎР‚
- Viber
- Skype
- Telegram
Возвращение значения при прыжках между функциями
В процессе разработки виртуальной машины мне понадобилось написать обработчик прерываний BIOS.
Если кратко то:
void bios_call(uint8_t code) {
switch(code) {
...
case 2:
goto NMI_CALL;
break;
...
}
int main()
{
...
NMI_CALL:
printf("Called interput NMI(int 2)\n");
system("pause");
return 1;
}
Из-за goto
я не знаю от какой функции return 1;
вернёт 1(bios_call
или main
).
Наверное понадобится что-то типа asm("pop")
, чтобы вернуть управление main()
Да, код не работает, да и прерывания должны находиться в IVT(в памяти), а не во внешней функции, так что вопрос бессмыслен, но из-за правил StackOverflow я не могу удалить(на вопрос уже ответили). Простите.
Ответы (3 шт):
Попробуй функции выхода из <stdlib.h>
, например exit
void bios_call(uint8_t code) {
switch(code) {
...
case 2:
printf("Called interput NMI(int 2)\n");
system("pause");
exit(1);
...
}
int main()
{
...
}
Есть два варианта решения вашей проблемы:
Первый вариант
Его предложил @HelloWorld в своём ответе. Я его несколько обобщу.
Суть решения: Уход от использования goto
(почему не стоит их использовать в высокоуровневых языках можете прочитать здесь или по первой ссылке в поисковике по запросу "почему не стоит использовать goto").
Например, можете либо писать код для действия прямо внутри case
, как предложил @HelloWorld, либо писать отдельные функции обработчики каждой инструкции:
// обработчик инструкции NMI_CALL
void NMI_CALL_handler() {
printf("Called interput NMI(int 2)\n");
system("pause");
exit(1);
}
void bios_call(uint8_t code) {
switch(code) {
...
case 2:
NMI_CALL_handler();
break; // если в обработчике будет exit, break не нужен
...
}
int main()
{
...
}
Второй вариант
Суть решения: использование списка (enum)
инструкций и обрабатывающего цикла.
Судя по приведенному вами ответу, структура вашей программы несколько нетипичная для C++
, попробуйте изменить структура вашей программы следующим образом:
enum Instructions {
INSTR_1 = 1,
NMI_CALL = 2,
...
};
...
// обработчик NMI_CALL
void NMI_CALL_handler() {
printf("Called interput NMI(int 2)\n");
system("pause");
exit(1);
}
...
// обработка итерации цикла
void execution_iter(uint8_t code) {
switch(code) {
...
case Instructions.NMI_CALL:
NMI_CALL_handler();
break;
}
}
// главный цикл обработки инструкций
void execution_loop(/* список инструкций */) {
for (/* цикл по списку */) {
uint8_t code = /* получить след. инструкцию из списка */
execution_iter(code);
}
}
int main()
{
...
execution_loop(/* список инструкций */);
...
}
Если за C++, то, очевидно, неким аналогом "прерываний" или межпроцедурного goto являются исключения:
void bios_call(uint8_t code) {
switch(code) {
...
case 2:
throw NMI_CALL;
...
}
}
int main()
{
try {
...
} catch(const NMI_CALL& e) {
printf("Called interput NMI(int 2)\n");
system("pause");
return 1;
}
}
Если за C, то аналог межпроцедурного goto это setjmp()/longjmp()
(при использовании в C++, не вызывают деструкторы объектов на стеке, т.е. строго говоря в C++ применимы только для использования функций POSIX с последующим жёстким _Exit()
, ни какого либерализма и ни каких return
для C++, собственно для чего их в стандарте C++, возможно, и сохранили):
void bios_call(uint8_t code) {
switch(code) {
...
case 2:
longjmp(NMI_CALL_buf, NMI_CALL_code);
...
}
}
int main()
{
if (setjmp(NMI_CALL_buf) {
// ветка возврата с NMI_CALL_code
printf("Called interput NMI(int 2)\n");
system("pause");
return 1;
}
....
}
Так же аналогом прерываний могут служить сигналы, но это больше про прерывания с обработкой, возвратом и продолжением.