Как (вычислить) goto и longjmp в C ++?

Обычно я не пишу C ++, но мой странный друг-компьютерщик устал от просмотра моих замечательных программ FORTRAN и попросил меня переписать одну из них на C ++, так как ему больше нравятся мои коды C ++. (Здесь мы делаем ставку на деньги.) Точные условия заключаются в том, что его нужно компилировать в современном компиляторе C ++. Может, он ненавидит хороший conio.h - не знаю.

Теперь я понимаю, что есть совершенно хорошие способы написания на C ++, но я собираюсь добиться здесь личной победы, пытаясь сделать мою версию C ++ как можно более похожей на FORTRAN. Что касается бонусных баллов, это может сэкономить мне время и силы при преобразовании кода.

ТАК! Это подводит меня к следующим связанным вопросам:

На gotos:

  1. Как вы работаете с goto?
  2. Какие ограничения на gotos в C ++?
  3. Есть вопросы по поводу объема? (Я собираюсь попытаться охватить как можно больше глобальных масштабов, но вы никогда не знаете.)
  4. Если я использую расширение GCC для перехода к массиву указателей void, есть ли какие-либо новые проблемы с поведением undefined и т. Д.?


В longjmp:

  1. Как безопасно использовать longjmp?
  2. Каковы ограничения longjmps в C ++?
  3. Что он делает для области видимости?
  4. Есть ли какие-то особые моменты, когда кажется, что longjmp должен быть безопасным, но на самом деле это не то, чего мне следует остерегаться?
  5. Как мне смоделировать вычисленный goto с помощью longjmp?
  6. Есть ли ощутимая польза от использования longjmp вместо goto, если в моей программе есть только одна функция?

Сейчас меня больше всего беспокоит, чтобы для этого работала вычисляемая команда goto. Похоже, я, вероятно, воспользуюсь longjmp для этой работы, потому что массив указателей void не является частью стандарта C ++, а специфическое расширение GCC.


person Code Maker    schedule 28.09.2011    source источник
comment
Призрачный поток неответов, осуждающих gotos в 3 ... 2 ... 1 ...   -  person Justin ᚅᚔᚈᚄᚒᚔ    schedule 28.09.2011
comment
Спасибо за попытку доказать, что в буквальном смысле настоящие программисты могут писать FORTRAN на любом языке :)   -  person    schedule 28.09.2011
comment
Если вы пишете C ++ в стиле FORTRAN, значит, вы пишете не C ++. Если бы я был на пари, вам было бы трудно убедить меня, что вы сделали свою часть работы.   -  person wilhelmtell    schedule 28.09.2011
comment
Можем ли мы хотя бы посмеяться над Фортраном?   -  person Ritch Melton    schedule 28.09.2011
comment
Я думаю, что раньше работал с этим парнем на моей старой работе!   -  person Didaxis    schedule 28.09.2011
comment
Вы можете высмеивать все, что хотите, но если вы опубликуете ответ, я ожидаю, что это будет правильный ответ. Кроме того, Вильгельмелл, в нашей ставке были точные условия.   -  person Code Maker    schedule 28.09.2011
comment
+1 за исходный вопрос, хотя лично я думаю, что вы делаете творческую попытку получить ответы на домашнее задание. :)   -  person AndersK    schedule 28.09.2011
comment
Андерс К., я почти уверен, что в наши дни действительно нет учителей C ++, которые заставляют использовать gotos и longjmps. Обычно они обещают нули, если вы их используете. А креатива вы еще не видели. Я подумываю о том, чтобы чертовски злоупотребить определениями и перегрузить, чтобы мне даже не пришлось переписывать свой FORTRAN.   -  person Code Maker    schedule 28.09.2011
comment
это меня помнит тот день, когда я реализовал механизм обработки исключений, ориентированный на Ada, на C, используя gotos, longjmp и #defines ... Мне было очень весело писать и тестировать это, но я никогда не мог использовать его в реальном мире, опасаясь гнев моих товарищей по работе.   -  person Adrien Plisson    schedule 28.09.2011
comment
Это реальный вопрос. То, что вам не нравится goto, еще не повод закрывать этот пост!   -  person John Dibling    schedule 28.09.2011
comment
Нетрудно сказать, о чем здесь спрашивают. Этот вопрос не является двусмысленным, расплывчатым, неполным, чрезмерно широким или риторическим, и на него можно разумно ответить в его нынешней форме. При голосовании за закрытие, пожалуйста, не выбирайте причину наугад.   -  person Troubadour    schedule 28.09.2011
comment
@John Dibling: Я проголосовал за закрытие как Неконструктивный, потому что писать намеренно сложный FORTRAN на C ++ и собирать рой goto - плохие комментарии, а дискуссии никому не помогают.   -  person AJG85    schedule 28.09.2011
comment
Связанный: stackoverflow.com/q/7334952/46642, stackoverflow.com/q/1376085/46642 и многие другие.   -  person R. Martinho Fernandes    schedule 28.09.2011
comment
@ AJG85, мое намерение может быть неконструктивным, конечно, но мой вопрос все еще совершенно конструктивен, и кто-то другой, смотрящий на этот вопрос, может иметь более конструктивную цель (например, отладка чужого кода или что-то еще).   -  person Code Maker    schedule 28.09.2011
comment
Вот что вам следовало попробовать , прежде чем спрашивать: stackoverflow.com/questions/tagged / c% 2b% 2b% 20longjmp и stackoverflow.com/questions/tagged/c%2b % 2b% 20goto   -  person R. Martinho Fernandes    schedule 28.09.2011
comment
@Р. Мартиньо Фернандес: Полезно? да. Отвечаете на все части моего вопроса? Нет.   -  person Code Maker    schedule 29.09.2011
comment
@CodeMaker: Почему это вопрос о C ++? Вы не используете ни одной функции C ++, которая недоступна в C. Вы не используете объекты, поскольку все является глобальным. Вы не используете шаблоны. Вы не используете какие-либо разумные структуры. Так что же в этом вопросе делает насчет C ++? Действительно, быть C ++ означает, что у вас есть возможность испортить все, что C не может.   -  person Nicol Bolas    schedule 29.09.2011
comment
@NicolBolas, я полагаю, потому что мой хороший друг попросил, чтобы я кодировал его на C ++, потому что goto и longjmp все еще составляют часть C ++, и потому что у меня должны быть опасения по поводу поведения и требований к gotos и longjmps в контексте C ++, где могут быть тонкие, но важные отличия от того, как они будут вести себя в C, чего я не делаю.   -  person Code Maker    schedule 29.09.2011
comment
Если я использую расширение GCC для перехода к массиву указателей void, есть ли какие-то новые опасения по поводу неопределенного поведения ‹- это точка, в которой моя голова взорвалась: ^)   -  person Jeremy Friesner    schedule 29.09.2011
comment
@NicolBolas: C ++ имеет лучшую безопасность типов, чем C.   -  person Janus Troelsen    schedule 28.09.2012


Ответы (7)


Я укушу и возьму голос против.

Я серьезно сомневаюсь, что вашему другу будет легче читать Фортран, написанный на C ++ (что, по сути, вы получите, если значительно используете goto и longjmp), и ему может быть даже труднее следовать. Язык C ++ сильно отличается от Fortran, и я действительно не думаю, что вам следует пытаться выполнить прямое преобразование из Fortran в C ++. Это только усложнит поддержку C ++, и вы также можете остаться с существующей кодовой базой.

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

longjmp: Нет причин предпочитать longjmp goto, если у вас есть только одна функция. Но если у вас есть только одна функция, опять же, вы действительно не пишете C ++, и в конечном итоге вам будет лучше, просто поддерживая свой Fortran.

person Mark B    schedule 28.09.2011
comment
Тогда ваша цель требует доработки. - person AJG85; 28.09.2011
comment
Я не понимаю, почему моя цель - твое дело. Вопрос все еще законный. - person Code Maker; 28.09.2011
comment
@Code Maker: Я просто думаю, что это более подходящая тема для бара за пивом, чем онлайн-форум вопросов и ответов. Никто другой не выиграет от ответа, написание преднамеренно сложного и запутанного кода не служит реальной цели, и, честно говоря, у вас больше шансов спровоцировать goto охоту на ведьм, чем получить какие-либо реальные ответы. - person AJG85; 28.09.2011
comment
@ AJG85, ответ моя нога никому не принесет пользы. Я задаю общие вопросы о goto и longjmps. Любой, кто хочет освежить в памяти эти вещи и обеспокоен любыми особенностями их использования, получит пользу от этого вопроса. - person Code Maker; 28.09.2011
comment
@CodeMaker Вы задаете общие вопросы о gotp и longjmps, на которые можно легко ответить, прочитав документацию. Если бы причина закрытия General Reference уже была реализована, я бы проголосовал за ее закрытие. Идеальным ответом на ваш вопрос был бы переработанный текст этой документации. - person R. Martinho Fernandes; 29.09.2011
comment
Ну, это не реализовано atm, и общие ссылки могут быть нечеткими, когда есть конкретные соображения компилятора и т. Д. В работе. Как я только что узнал, GCC позволяет использовать указатели void для меток goto. Это все меняет. - person Code Maker; 29.09.2011
comment
@CodeMaker: На общий вопрос о goto и longjmps в C ++ можно ответить очень просто. Использование goto, когда не используется goto, сделает ваш код более запутанным, чем goto. И longjmp уничтожает автоматические переменные, поэтому вам никогда не следует использовать его в C ++. Как работает goto - это то, чему учит любая книга по C ++. Расширения GCC явно не C ++ и поэтому не являются частью того, как goto работает. Так что да, все, о чем вы просили, является общим справочным материалом, или все, что вы просили и ответили раньше. - person Nicol Bolas; 29.09.2011
comment
@NicolBolas: я спрашиваю о выполнении вычисленного поведения типа goto и о том, как использовать longjmp в C ++. И поскольку вы так любезно подчеркнули, что longjmp делает проблемные вещи для C ++ и, следовательно, его избегают, тем более важно знать об использовании и рисках longjmp в C ++, которые, по-видимому, недостаточно документированы. Кстати, этот вопрос не зря помечен тегом language-extension. - person Code Maker; 29.09.2011
comment
@CodeMaker: вы не можете задокументировать что-то, что является неопределенным поведением, как сказано в спецификации C ++. Что ж, можно, но это будет бесполезная документация, поскольку она будет меняться всякий раз, когда вы меняете компилятор. Или фаза луны. Или, если по комнате дул резкий ветерок. Это все равно, что спрашивать, каково поведение доступа к освобожденной части памяти. - person Nicol Bolas; 29.09.2011
comment
@NicolBolas Верно. И это доказывает, что мы вышли за рамки общих ссылок. Longjmp все еще существует для использования, но недокументированный характер его рискованности побуждает меня задать вопрос о том, какие обстоятельства могут не интуитивно вызвать проблемы и какие соображения следует принять во внимание, чтобы использовать его относительно безопасно. - person Code Maker; 29.09.2011

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

Используйте goto, чтобы переместить указатель инструкции на «метку» в вашем коде, которая представляет собой идентификатор C ++, за которым следует двоеточие. Вот простой пример работающей программы:

#include <iostream>
#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
    int i = 0;
step:
    cout << "i = " << i;
    ++i;
    if( i < 10 )
        goto step;

}

В данном случае step: - это метка.

Есть опасения по поводу контекста.

  • Вы можете использовать только goto метку внутри текущей функции.
  • Если ваш goto пропускает инициализацию переменной, вы можете вызвать Неопределенное поведение (код, который будет компилироваться, но вы не можете точно сказать, что он будет делать на самом деле.).
  • Вы не можете goto войти в try блок или catch обработчик. Однако вы можете goto выйти из try блока.

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

person John Dibling    schedule 28.09.2011
comment
Спасибо. И я думаю, вы могли меня неправильно понять. Я хотел спросить: можно ли использовать метки перехода в качестве указателей, массивов или векторов для целей оператора goto? - person Code Maker; 28.09.2011
comment
OP говорит: Я обычно не пишу C ++. Возможно, расширите аббревиатуру UB до неопределенного поведения или дайте краткое определение. - person Robᵩ; 28.09.2011
comment
@Code: Вы имеете в виду, что хотите, например, хранить метки перехода в векторе? - person John Dibling; 28.09.2011
comment
@JohnDibling, кстати, знаете ли вы, будет ли метка указателя void GCC делать что-нибудь с этими пределами? - person Code Maker; 29.09.2011

Я думаю, что эта ссылка содержит большую часть информации, которую вы ищете.

goto

longjmp

person ronag    schedule 28.09.2011
comment
Я бы не стал называть MSDN справкой, скорее справочником :) (В нем говорится: Описывает язык программирования C ++, реализованный в Microsoft C ++.) - person Emile Vrijdags; 28.09.2011

вычислено goto -> switch

На самом деле у них есть (общая, но не универсальная) подчиненная реализация в виде таблицы переходов.

person dmckee --- ex-moderator kitten    schedule 28.09.2011
comment
Только иногда, если у переключателя есть только несколько вариантов, он, скорее всего, будет реализован как серия операторов if / else if. - person Daemin; 29.09.2011
comment
Конечно, и компилятор мог выбрать ту же реализацию для вычисляемого goto. - person dmckee --- ex-moderator kitten; 29.09.2011
comment
Оператор switch представляет собой только переход вперед. Я мог бы приблизиться к вычисленному goto, выполнив computed_goto: switch (goto_variable) { ... } раньше, поэтому я мог бы сделать goto_variable = 5; goto computed_goto;, но я надеюсь использовать здесь longjmp (). Я помню, как делал это с Java, но вместо этого использовал только помеченный цикл while (true) и инструкцию continue, но, увы, Java не так удобна для устройств Duff. - person Code Maker; 30.09.2011

Если я понимаю исходный вопрос, вопрос действительно интересный. Перефразируя вопрос (на то, что я считаю эквивалентным вопросом): «Как вы выполняете вычисляемый для FORTRAN goto в C?»

Сначала нам нужно узнать, что такое вычисляемый goto: Вот ссылка на одно объяснение: http://h21007.www2.hp.com/portal/download/files/unprot/fortran/docs/lrm/lrm0124.htm.

Пример вычисленного GOTO:

    GO TO (12,24,36), INDEX

Где 12, 24 и 36 - номера выписок. (Метки языка C могут служить эквивалентом, но это не единственное, что может быть эквивалентом.)

И где ИНДЕКС - переменная, но может быть результатом формулы.

Вот один из способов (но не единственный) сделать то же самое в C:

int SITU(int J, int K)
{
int raw_value = (J * 5) + K;

int index = (raw_value % 5) - 1;

return index;
}


int main(void)
{
int J = 5, K= 2;

// fortran computed goto statement: GO TO (320,330,340,350,360), SITU(J,K) + 1
switch (SITU(J,K) + 1)
{
case 0: // 320
    // code statement 320 goes here
    printf("Statement 320");
    break;
case 1: // 330
    // code statement 330 goes here
    printf("Statement 330");
    break;
case 2: // 340
    // code statement 340 goes here
    printf("Statement 340");
    break;
case 3: // 350
    // code statement 350 goes here
    printf("Statement 350");
    break;
case 4: // 360
    // code statement 360 goes here
    printf("Statement 360");
    break;
}

printf("\nPress Enter\n");
getchar();
return 0;
}

В этом конкретном примере мы видим, что вам не нужны C goto для реализации вычисляемого goto FORTRAN!

person Indinfer    schedule 11.09.2012
comment
Повторите свое последнее предложение: но оператор switch - это просто расширенная (многоцелевая) форма goto. - person Marc van Leeuwen; 26.04.2015

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

person John Humphreys    schedule 28.09.2011
comment
При низкой низкой стоимости полностью неопределенного поведения во многих сценариях. - person Billy ONeal; 28.09.2011
comment
Судя по всему, он пытается написать сложный код, чтобы выиграть пари - я бы никогда не стал трогать goto или longjjmp в реальном коде - они оба сложны в первую очередь. :п - person John Humphreys; 28.09.2011

Существует расширение GCC под названием Ярлыки как значения < / strong>, который поможет вам написать код для гольфа, по сути, предоставив вам вычисляемый goto. Конечно, вы можете создавать этикетки автоматически. Вам, вероятно, понадобится это сделать, поскольку вы не можете знать, сколько байтов машинного кода будет генерировать каждая строка.

person Janus Troelsen    schedule 27.09.2012