Привіт, світ, який обробляє помилки


9

Напишіть програму або функцію з такою функціональністю:

  • Програма / функція спочатку намагається записати рядок Hello, world!у стандартний вихідний потік. (Жодна інша форма виводу не є прийнятною для цього виклику, оскільки в основному фокус робиться на введення-виведення, а не на тривіальну поведінку самої програми.) Залежно від того, чи вдалось це зробити:
    • Якщо це вдалося вивести Hello, world!, програма / функція завершується без подальшої поведінки.
    • Якщо не вдалося створити правильний висновок через помилку, програма / функція намагається записати рядок Error writing "Hello, world!"у стандартний потік помилок. (Для цілей цього виклику вам не потрібно обробляти помилки для самої обробки помилок.)

Роз'яснення

  • Ваша програма / функція буде запускатися без вводу (якщо тільки вона написана мовою, яка абсолютно не потребує введення для роботи; в такому випадку вона буде працювати з найпростішим можливим введенням).

  • Виробляючи вихід, ви можете також створити один зворотний новий рядок, якщо бажаєте, але це не обов'язково.

  • Визначення "помилки запису до стандартного виводу", яке реалізує ваша програма, повинно розглянути як мінімум такі випадки як помилки:

    • Стандартний вихід не існує (тобто stdoutзакритий файл файлів, дескриптор файлу 1 не існує, але ці випадки перекладаються на мову та ОС, які ви використовуєте);
    • Стандартний вихід, що стосується файлу на диску, у якому не залишилося вільного місця;
    • Стандартний вихід, що підключається до іншої програми, яка вже закрила свій кінець з'єднання.

    і має сприймати принаймні такі випадки як успіх (тобто не помилка):

    • Стандартний вихід підключається до терміналу і Hello, world!відображається на екрані.
    • Стандартний вихід підключається до файлу і Hello, world!записується у файл.

    Ви можете вибрати деталі того, що вважається помилкою виводу, якщо це відповідає вищевказаним правилам.

  • Ваша програма / функція не повинна виходити з ладу при зіткненні з будь-якою з перелічених вище ситуацій з помилками. Ви вирішуєте, яким кодом виходу користуєтесь.

  • Ваша програма / функція не повинна описувати характер виниклої помилки у стандартному потоці помилок; він повинен просто надрукувати рядок, зазначений вище. Стороннє виведення стандартної помилки (наприклад, попередження компілятора) є законним лише тоді, коли воно виробляється беззастережно, незалежно від того, виникає помилка чи ні.

  • Вашій програмі потрібно працювати лише в одній операційній системі (хоча вона повинна бути такою, на якій помилки, перераховані вище, мають сенс; я намагався тримати їх достатньо загальними для роботи на більшості багатозадачних операційних систем споживачів, але, більш дивні операційні системи цілком можуть бути виключено з цього виклику). Якщо ваша програма нерепортажна, перелічіть припущення, які вона потребує для виконання, у назві вашої заявки.

  • Це завдання може бути неможливим на всіх мовах (не кожна мова дозволяє програмі обробляти помилки виводу у користувальницький спосіб). Вам доведеться вибрати мову там, де це можливо.

  • Переконайтесь, що ваша програма / функція працює! Не просто довіряйте документації функцій бібліотеки, щоб робити те, що вони говорять. Поводження з помилками простих вихідних функцій часто виявляється порушеним на практиці, навіть якщо функції теоретично обробляють помилки.

Тестові справи

Ось спосіб імітувати кожне з вищезазначених умов помилок при використанні bashв Linux (вам не потрібно використовувати Linux, але це, мабуть, найпростіша система для перевірки цього):

your_program_here >&-           # nonexistent stdout
your_program_here > /dev/full   # out of disk space
mkfifo test  # note: change "test" to a filename that isn't in use
true < test &
your_program_here > test        # connecting to a program that doesn't want input
rm test      # clean up the FIFO we used earlier

Перші дві тестові шкали детерміновані. Останнє не (воно покладається на умову перегонів); з метою тестування рекомендую додати затримку між початком вашої програми та фактичним результатом до стандартного виводу, щоб забезпечити вирішення стану гонки таким чином, що викриває помилку.

Стан перемоги

Це виклик, тим коротше - краще. Як (майже) завжди, ми вимірюємо довжину програми в байтах.


1
Чи знаєте ви, чи є спосіб перевірити це в Windows? Я можу перевірити перший критерій, але не частину щодо заповнення диска ...
Стюі Гріффін

Щоб зменшити стан гонки, ви могли б використовувати sleep 1 < test; (sleep 2; your_program_here) > test?
Ніл

Відповіді:


6

Баш , 71 60 байт

h=Hello,\ world!
(echo $h)2>&-||echo Error writing \"$h\">&2

Спробуйте в Інтернеті!

Як це працює

Після збереження Hello, world!до змінної h робимо наступне.

По-перше, (echo $h)2>&-спроби друку Hello, world!на STDOUT. 2>&-потрібен для запобігання відображенню повідомлення про помилку ехо: помилка запису: неправильний дескриптор файлу у випадку відмови запису. Оскільки запис в іменовану трубу, яка не приймає вхід, вбила б Bash програму з сигналом 13 (SIGPIPE), ми виконуємо команду в subhell ( (...)), тож буде знищено лише нижню частину.

Нарешті, якщо друк на STDOUT не вдався, з підпрограми вийде з ненульовим кодом статусу (141 для SIGPIPE, 1 для загальної помилки), тому echo Error writing \"$h\">&2друкується потрібне повідомлення на STDERR.




1

C (gcc) , 87 86 байт

f(){signal(13,1);write(1-puts("Hello, world!"),"Error writing \"Hello, world!\"",29);}

Спробуйте в Інтернеті!

Безумовно

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void f(void)
{
    signal(SIGPIPE, SIG_IGN); // Works (and is required) on TIO. YMMV
    int fd = (puts("Hello, world!")) < 0 ? 2 : -13;
    write(fd, "Error writing \"Hello, world!\"", 29);
}

як ви знаєте, що ставить прибуток? тут сказано, що це просто> = 0, щоб все було гаразд
RosLuP

putsповертає кількість записаних байтів або -1 у випадку помилки, тому вона або повертає 14 (Hello World плюс новий рядок), або -1 . (Це може бути залежно від платформи, але це так, як він поводиться з glibc.)
Денніс

K & R2 каже, що повертає EOF [-1 практично], якщо помилка; або значення не від'ємне, якщо все нормально
RosLuP

1
На PPCG мови визначаються їх реалізацією, і gcc / glibc веде себе так, як я сказав.
Денніс

я віддаю перевагу старій книзі
RosLuP

1

PowerShell, 80 байт

try{echo($h="Hello, World!") -ea 4}catch{$host.ui|% *rL* "Error writing ""$h"""}

пояснив:

try{
    #Attempt to 'echo' (write output) the string, and assign it to $h
    #Make sure the 'error action' is set to '4' to make it a terminating error.
    echo($h="Hello, World!") -ea 4
} catch { 
    #Use the "WriteErrorLine" function in $host.ui to stderr
    $host.ui|% *rL* "Error writing ""$h"""
}

не вдалося насправді спробувати це, коли він помиляється, але, безумовно, ~ має працювати.


Повідомлення про помилку має бути записано в STDERR . Записати його в STDOUT неможливо, якщо під час першої спроби запису сталася помилка.
Денніс

@ Денніс спасибі за це, оновлений там, питання не прочитав повністю.
colsw

Afaict PowerShell ловить лише фатальні винятки, тому вам знадобиться Write-Host -ErrorAction Stopщось подібне. Крім того, throwвиробляється додаткова анормація налагодження, крім рядка, який він повинен надрукувати, який, до речі, повинен мати малий W і подвійні лапки навколо рядка HW.
Денніс

@Денніс додаткова інформація про налагодження мене розчавила, відповідь оновлена ​​зараз.
colsw

1

Javascript, 79 76 байт

try{(l=console).log(a="Hello, world!")}catch(e){l.error('Error writing '+a)}

Зауважте, що рядок, який ви повинні вивести, - 'Hello, world!'це на один байт довше, ніж ви використовуєте. Крім того, я припускаю, що призначення aвсередині дзвінка console.logбуде коротшим (1B), а вилучення крапки з комою після l.log(a)збереження іншого байта.
Лука

@Luke Спасибі, це була досить велика помилка!
Matthew Roh

1
try{(l=console).log(a="Hello, world!")}catch(e){l.error('Error writing '+a)}за 76 байт. Спочатку consoleпризначається l, потім "Hello, world!'призначається a, а потім виконується.
Лука

0

Perl 5, 51 байт

вимагає -M5.01, що безкоштовно

say$h="Hello, world!"or die"Error writing \"$h\"$/"

Тестується в Strawberry Perl 5.24.0, запустивши програму як є (надруковано на стандартний вихід) та запустивши

print f $h="Hello, world!"or die"Error writing \"$h\"$/"

(друкується до стандартної помилки). Я не знаю, як перевірити наявність інших помилок за допомогою Полуниці, але з ними слід обробляти те саме….


Наскільки я можу сказати, це не працює. tio.run/nexus/bash#jY3NDoIwEITvfYq1IXCiiD83ys3Ei2/… (У рядку також відсутня кома.)
Денніс

Я не знаю, що робити із тією сторінкою, на яку ви пов’язані; ви можете пояснити, будь ласка? Також зауважте, що сценарій повинен працювати лише на одній ОС. І я додам кома; Дякую.
msh210

Вихідні дані повинні відображатися Hello, world!після, === 1 ===а нічого після інших. Налагодження не повинно відображати нічого після === 1 ===та Error writing "Hello, world!"після інших. Я знаю, що ваша програма не повинна працювати над TIO, але print f...показує призначені повідомлення про помилки, тоді як оригінальна програма не робить.
Денніс

"Вихід" і "Налагодження", як я бачу, нічого не відображають. Я також не знаю, якими мають бути розділи "Заголовок" та "Футер". І я зовсім не знайомий з TIO, але зауважте, що Strawberry Perl працює на MS Windows.
msh210

Хет-підказка Деннісу за ідею зберігати рядок у змінній (хоча я, мабуть, подумав би про це, якби я її там не бачив).
msh210

0

REXX, 111 106 байт

signal on notready
a='Hello, world!'
_=lineout(,a)
exit
notready:_=lineout('stderr','Error writing "'a'"')

Програма покладається на те, що існує потік під назвою "stderr". Напевно, це не так у системах IBM.


0

C, 77 байт

f(a){a="Error writing \"Hello, world!\"";write(1,a+15,13)-13&&write(2,a,29);}

для дзвінка

main(){f(1); return 0;}

На якій платформі ви протестували це? Він не працює в Linux, якщо виникає зламана труба.
Денніс

0

R , 91 байт

s="Hello, world!"
tryCatch(cat(s),error=function(e)cat('Error writing "','"',file=2,sep=s))

Спробуйте в Інтернеті!

Я спробував помилитися, запустивши його cat(s,file=12)замість cat(s), і він друкує правильний текст у stderr. Це invalid connectionінакше помилка.


Будь-яка ідея, як перевірити на інші вихідні помилки?
JayCe
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.