Есть ли способ восстановиться после ошибки printf()/puts()?

Пока интерпретирую и транспилирую Brainfuck, у меня есть серия обращений к printf()/puts():

while (ip < ops->count) {
        Op op = ops->items[ip];

        switch (op.kind) {
            case '+':
                printf("    t.mem[t.head] += %zu;\n", op.operand);
                ++ip;
                break;
            case '-':
                printf("    t.mem[t.head] -= %zu;\n", op.operand);
                ++ip;
                break;
            case '.':
                printf("    xputchar_many(&t, %zu);\n", op.operand);
                ++ip;
                break;
            case ',':
                printf("    xgetchar_many(&t, %zu);{\n", op.operand);
                ++ip;
                break;
            case '>':
                printf("    t.head += %zu;\n\n"
                       "    grow_tape_and_append_many_zeroes(&t);\n", op.operand);
                ++ip;
                break;
            case '<':
                printf("    t.head = t.head < %zu ? t.count - (%zu - t.head) : t.head - %zu;\n",
                       op.operand, op.operand, op.operand);
                ++ip;
                break;
            case '[':
                puts("    while (t.mem[t.head] != 0) {");
                ++ip;
                break;
            case ']':
                puts("    }");
                ++ip;
                break;
        }
    }

Вызовы puts()/printf() генерируют код.

У меня есть два вопроса:

Есть ли шанс на восстановление после сбоя printf() (т. е. возврата отрицательного целого числа) или сбоя puts() (т. е. возврата EOF)? (Я придерживаюсь мнения, что нет.)

Если нет, то полезен ли вызов fprintf(stderr, ...) перед выходом? (Я считаю, что да.)

Да, мне следует переместить ++ip в конец switch утверждения.

Harith 18.03.2024 10:07
Is there any chance of recovery after printf() returns a negative value?" что ты имеешь в виду?
gulpr 18.03.2024 10:09

@gulpr Я обновил вопрос. Это все еще неоднозначно?

Harith 18.03.2024 10:12

Если да, то ваша система или программа мертва и восстановление невозможно :)

gulpr 18.03.2024 10:15

Это в контексте, когда стандартный вывод перенаправляется в какую-то другую форму вывода, например в файл или последовательный порт? Иначе я не понимаю проблемы.

Lundin 18.03.2024 10:32

@Lundin printf()/puts() можно заменить на fprintf()/fputs() и вывести в какой-нибудь файл. stdout можно перенаправить. Проблема заключается в неправильно сгенерированном коде или наполовину сгенерированном коде без индикации ошибки.

Harith 18.03.2024 10:34

Я не понимаю значения примера кода; Я предположил, что это не имеет значения, и ответил буквально на вопрос. Если вы считаете, что ваш код и xputchar_many в чем-то важны, уточните.

anatolyg 18.03.2024 10:58

@anatolyg Звонки на puts()/printf() были важной частью. Пример кода был добавлен, потому что есть разница в генерации кода с помощью printf() и выводе "Hello World." на консоль (для чего я бы не стал проверять возвращаемое значение). Хотя я удалил часть, говорящую о xputchar_many(). Спасибо.

Harith 18.03.2024 11:09
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
8
106
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

В принципе да. В заголовочном файле <stdio.h> есть специальная функция clearerr, предназначенная именно для этого. Вы можете попробовать отобразить ошибку, используя perror, попробуйте сделать clearerr и повторите попытку.

Возможный вариант использования, предложенный Эриком Постпишилом:

Вы пишете логи на какое-то устройство. Он заполняется, а puts возвращает ошибку из-за нехватки места. Вы [...] удаляете старые файлы журналов и повторяете попытку.

На сайте cppreference приведен слегка запутанный пример ошибки, которая мне кажется исправимой (я не пробовал):

setlocale(LC_ALL, "en_US.utf8");

errno = 0;
if (fputwc(L'🍌', stdout) == WEOF)
{
    if (errno == EILSEQ)
        puts("Encoding error in fputwc.");
    else
        puts("I/O error in fputwc.");
    return EXIT_FAILURE;
}

Если в stdout есть ошибки, stderr все равно можно будет записать! Распространенным примером является перенаправление (вы можете перенаправить stdout с помощью оболочки или freopen, оставив stderr подключенным к консоли).

Вместо puts() в примере кода рассмотрите perror();.

chux - Reinstate Monica 18.03.2024 12:43

Быть «Но я не могу представить ситуацию, когда это может быть полезно на практике»: Вы пишете логи на какое-то устройство. Он заполняется, а puts возвращает ошибку из-за нехватки места. Вы ищете и удаляете старые файлы журналов и повторяете попытку.

Eric Postpischil 18.03.2024 12:56
Ответ принят как подходящий

Есть ли шанс на восстановление после сбоя printf() (т. е. возврата отрицательного целого числа) или сбоя puts() (т. е. возврата EOF)? (Я придерживаюсь мнения, что нет.)

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

Однако вы, вероятно, задаете неправильный вопрос. Вы пишете транспилятор Brainfuck. Первые два вопроса, которые вам следует задать здесь:

  • Стоит ли пытаться восстановиться после ошибок ввода-вывода?

    и

  • Если нет, то что следует сделать вместо этого?

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

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

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

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

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

Могут быть и другие признаки, которые программа может предоставить. Например, как отметил @JonathanLeffler в комментариях, если выходные данные будут направлены в обычный файл, путь к которому известен программе, то она может попытаться удалить этот файл при завершении из-за ошибки ввода-вывода. Желательно ли то или иное подобное поведение, решать вам.

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

Jonathan Leffler 18.03.2024 16:16

Согласен, @JonathanLeffler, хотя, конечно, удаление тоже может не удаться. Например, если проблема возникла в первую очередь из-за того, что файловая система была размонтирована или перемонтирована только для чтения. Я бы охарактеризовал удаление выходного файла как возможное дополнительное поведение в режиме сбоя, доступное, когда местом назначения был файл, путь к которому был известен программе.

John Bollinger 18.03.2024 16:44

Другие вопросы по теме