LINUX.ORG.RU

Наилучшая стратегия обработки ошибок в Си

 


1

4

Нагуглил, что рекомендуют сделать enum и какое-то текстовое представление, которое можно будет получить через коды. В общем, на сколько я понял что-то вроде errno. Но вот в чём вопрос: как лучше сделать, чтобы функция возвращала код ошибки

 MYERROR create_some_thing (SOME_THING **ptr/*other parameters*/);
глобальная переменная
 SOME_THING *create_some_thing (/*other parameters*/);
или указатель в списке параметров функций?
 SOME_THING *create_some_thing (/*other parameters*/, MYERROR* ptr);

Deleted

Последнее исправление: av0r (всего исправлений: 2)
Ответ на: комментарий от monk

От того, что STL описана в стандарте, она не перестала быть сторонней библиотекой. Более того, наличие STL в стандарте затрудняет взаимодействие с Qt, VTK и прочими библиотеками (ну как быстро преобразовать vector<string> в vtkStringArray?).

Давайте доведем феерию до апупея и закончим полным апупеозом:

От того, что strlen описана в стандарте, она не перестала быть обычной функций из сторонней библиотеки. Более того, наличие strlen в стандарте затрудняет взаимодействие с Qt, VTK и прочими библиотеками (ну как узнать с помощью strlen длину QString?).

eao197 ★★★★★
()
Ответ на: комментарий от loz

Ты правда с такой логикой код пишешь?

твоего кода я вообще не заметил, мешает ли мне это писать код ? нет.

anonymous
()
Ответ на: комментарий от monk

Если я правильно понял, то вариант с union не переносимый. Так что пока склоняюсь к структуре.

Deleted
()
Ответ на: комментарий от eao197

От того, что strlen описана в стандарте, она не перестала быть обычной функций из сторонней библиотеки.

Разумеется.

ну как узнать с помощью strlen длину QString?

strlen(qstr.c_str())

Совместимость с char* поддерживается гораздо лучше, чем с std::string

monk ★★★★★
()
Ответ на: комментарий от Deleted

Где здесь хоть слово о «хороший язык»/«плохой язык»?

Наверное, когда к вопросу о жирноте примешалось использование или нет сторонних библиотек.

monk ★★★★★
()
Ответ на: комментарий от tailgunner

Так лучше?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>

#include "list.h"

struct dnode
{
    struct list_head list;
    char name[0];
};


int main(int argc, char* argv[])
{
    struct list_head dnlist;
    struct dnode *dn, *n;
    struct dirent *entry;

    if (argc != 2) {
        fprintf(stderr, "Usage: %s DIR\n", argv[0]);
        return 1;
    }

    DIR *dir = opendir(argv[1]);
    if (dir == NULL) {
        perror("opendir");
        return 1;
    }

    INIT_LIST_HEAD(&dnlist);
    while ((entry = readdir(dir)) != NULL) {
        int len = strlen(entry->d_name);
        struct dnode *dn = malloc(sizeof(*dn) + len + 1);
        if (!dn)
            break;
        memcpy(dn->name, entry->d_name, len + 1);
        list_add_tail(&dn->list, &dnlist);
    }

    list_for_each_entry_safe(dn, n, &dnlist, list) {
        printf("%s\n", dn->name);
        free(dn);
    }

    closedir(dir);
    return 0;
}

anonymous
()
Ответ на: комментарий от Deleted

К вопросу о жирноте. Компилирую test.c с GLib и test.c++ - твой.

$ gcc -lglib-2.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -o out.c -O3 test.c
$ g++ -o out.c++ -O3 test.c++              
$ strip out*
$ ls -l out*
-rwxr-xr-x 1 monk monk  6304 авг  3 18:02 out.c
-rwxr-xr-x 1 monk monk 10488 авг  3 18:02 out.c++

Внешние библиотеки: GLib занимает 1.1МБ, stdc++ — 1.6МБ.

monk ★★★★★
()
Ответ на: комментарий от Deleted

Если я правильно понял, то вариант с union не переносимый. Так что пока склоняюсь к структуре.

Переносимый. Например так:

typedef struct {
  char is_error;
  union {
    some_error_type error;
    some_data_type data;
  } x;
}

Единственное неудобство — надо писать result.x.data чтобы добраться до данных. Но это прекрасно оборачивается в функции или define'ы.

monk ★★★★★
()
Ответ на: комментарий от anonymous

Так лучше?

Нет. Еще больше похоже на подростковые понты «я крутой - я никогда не забываю прибавить 1 к sizeof».

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Чего люди только не придумают, чтобы не писать на Rust, ML или хотя бы Си++.

Rust и ML не везде есть, а Си++ без исключений использовать сложно, а с исключениями крайне ненадёжно (фактически, получаем ещё один путь программы на каждую операцию, потенциально бросающую исключение).

monk ★★★★★
()
Ответ на: комментарий от monk

а Си++ без исключений использовать сложно

А подробнее? Недавно читал, что Си++ без исключений используется то ли 40% прогеров, то ли больше.

P.S. в Си++ можно сделать типово-безопсный tagged union и возвращать его. Исключения не использовать.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

А подробнее? Недавно читал, что Си++ без исключений используется то ли 40% прогеров, то ли больше.

Нельзя использовать функции из std, которые могут бросать исключения: new, std::vector.at, std::vector.push_back ...

При использовании сторонних библиотек аналогичное ограничение.

monk ★★★★★
()
Ответ на: комментарий от monk

а с исключениями крайне ненадёжно

До апупея, оказывается, было еще далеко. Доказательство, вероятно, будет такое же яркое и убедительное, как применение strlen к QString-у.

eao197 ★★★★★
()
Ответ на: комментарий от monk

Нельзя использовать функции из std, которые могут бросать исключения: new, std::vector.at, std::vector.push_back ...

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

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

_Ты_, автор программы, можешь не использовать исключений, а к исключениям из std относиться как к фатальным ошибкам.

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

monk ★★★★★
()
Ответ на: комментарий от spec_po_kiskam

У сишников до CLion вообще нормальной IDE

Как будто CLion нормальный.

RazrFalcon ★★★★★
()
Ответ на: комментарий от eao197

Доказательство, вероятно, будет такое же яркое и убедительное, как применение strlen к QString-у.

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

monk ★★★★★
()
Ответ на: комментарий от monk

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

Я не знаю, откуда ты взял эту посылку и этот вывод, но и то, и другое неверно.

tailgunner ★★★★★
()
Ответ на: комментарий от monk

Вот так незаметно для зрителей обсуждение переходит от «ненадежности» к «невозможности доказательства корректности». Вечер акуительных открытий продолжается.

eao197 ★★★★★
()
Ответ на: комментарий от monk

исключениями крайне ненадёжно (фактически, получаем ещё один путь программы на каждую операцию, потенциально бросающую исключение)

Ошибки обрабатывать вообще сложно. Без исключений получаем, что нужно обрабатывать каждую ошибку в месте её возникновения или передавать её дальше руками. То есть делаем абсолютно тоже самое, что и с исключениями, только скорее всего костыльно и руками.

oldstable
()
Ответ на: комментарий от monk

Си++ без исключений использовать сложно

Миллионы строк на Qt смотрят на вас с непониманием.

RazrFalcon ★★★★★
()
Ответ на: комментарий от tailgunner

Я не знаю, откуда ты взял эту посылку и этот вывод, но и то, и другое неверно.

В смысле, есть какой-то метод быстро определить, может ли, например a = b + c бросить исключение или нет? Насколько я помню, в C++ исключения можно бросать из любой операции.

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

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

monk ★★★★★
()
Ответ на: комментарий от eao197

от «ненадежности» к «невозможности доказательства корректности»

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

monk ★★★★★
()
Ответ на: комментарий от monk

В смысле [...]

Нет.

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

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

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 2)
Ответ на: комментарий от monk

Так это одно и то же.

В теории. На практике корректность огромного количество реально работающего софта никто не доказывает из-за невозможности практического осуществления этого самого доказательства. Что не препятствует написанию надежного софта.

Или ты доказываешь, что для всех входных данных твой кусок кода отрабатывает корректно, или просто проверяешь пару тестов и надеешься на авось.

Отрабатывает корректно != работает надежно, вообще-то говоря. Когда говорят про корректность, то говорят про соответствие кода заданной спецификации. А вот заложена ли надежность в эту самую спецификацию — это уже совсем другой вопрос.

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

Это вы на динамически-типизированных языках слишком много программировали (если вообще программировали, а не для души в свободное время пописывали).

eao197 ★★★★★
()
Ответ на: комментарий от monk

Потому-что такова была задача. :-)

Задача была в демонстрации абсурдности вашего высказывания, с чем вы прекрасно и справились без посторонней помощи.

eao197 ★★★★★
()
Ответ на: комментарий от oldstable

Без исключений получаем, что нужно обрабатывать каждую ошибку в месте её возникновения или передавать её дальше руками.

Без исключений все возможные ошибочные ситуации становятся частью возвращаемого типа. А значит, если они все обработаны, то никаких неожиданностей быть уже не может.

только скорее всего костыльно и руками

В Rust и Haskell не так уж и костыльно. Почти идеальный вариант в Zig

fn doAThing(str: []u8) -> %void {
    const number = %return parseU64(str, 10);
    // ...
}

%void = тип void | error

%return x = if (is_error(x)) return x; else x;

Всё это легко делается на макросах в C/C++.

monk ★★★★★
()
Ответ на: комментарий от eao197

Задача была в демонстрации абсурдности вашего высказывания

Если попробуете сконвертировать vector<string> в vtkStringArray, то увидите, что это намного сложнее.

И если длину строки в Qt узнать можно, то в vtkFieldData std::vector не запихнуть.

monk ★★★★★
()
Ответ на: комментарий от monk

Без исключений все возможные ошибочные ситуации становятся частью возвращаемого типа.

Доо. Особенно с unwrap.

Всё это легко делается на макросах в C/C++.

Доо. Сделай на Си++ макрос хотя бы уровня растового try.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 2)
Ответ на: комментарий от monk

Абсурдность касалась не сложности конвертации типов, которые ничего не знают друг о друге. А пассажа про то, что STL осталась обычной сторонней библиотекой.

Это увлечение Lisp-ом заставляет насколько альтернативно смотреть на мир?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

На практике корректность огромного количество реально работающего софта никто не доказывает из-за невозможности практического осуществления этого самого доказательства. Что не препятствует написанию надежного софта.

Можете пример надёжного софта привести? А то новые CVE регулярно. В 1996 даже ракета Ариан-5 упала, а в 2017 — Союз.

Это вы на динамически-типизированных языках слишком много программировали (если вообще программировали, а не для души в свободное время пописывали).

Писал и на динамически типизированных и на хаскеле и на C++98. На С++ единственным вариантом, дающим более-менее детерминированную программу был catch(...) на каждой функции. В этом смысле даже 1С лучше, так как там исключение предполагает, что оно просто будет показано пользователю.

monk ★★★★★
()
Ответ на: комментарий от monk

Можете пример надёжного софта привести? [...] В 1996 даже ракета Ариан-5 упала

Вот, например, Ариан-5 - надежный софт. За 20 лет - один сбой.

На С++ единственным вариантом, дающим более-менее детерминированную программу был catch(...) на каждой функции.

Что такое «более-менее детерминированная программа» и чем она отличается от просто «детерминированной»?

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от eao197

Это увлечение Lisp-ом заставляет насколько альтернативно смотреть на мир?

Скорее то, что на C++ я начал писать до того, как появилась STL. Поэтому для меня нынешняя ситуация аналогична тому, что в стандарт C2018 внесут GLib и GObject. Или даже сразу GTK, чего уж мелочиться.

monk ★★★★★
()
Ответ на: комментарий от monk

Можете пример надёжного софта привести?

Вероятно, вы хотите примеров _абсолютно надежного_ софта. Это там же, где и сферические кони в вакууме.

По сути же вам tailgunner уже ответил. В том числе и про пример с Ariane-5.

eao197 ★★★★★
()
Ответ на: комментарий от monk

Скорее то, что на C++ я начал писать до того, как появилась STL.

Вы будете удивлены, но здесь вы не один такой. Тем не менее, другие «ветераны» как-то более реалистично на жизнь смотрят.

Поэтому для меня нынешняя ситуация аналогична тому, что в стандарт C2018 внесут GLib и GObject. Или даже сразу GTK, чего уж мелочиться.

Ну да, речь про альтернативное восприятие действительности. У вас вот GLib в стандарте C2018 (да и сам оный стандарт в наличии).

eao197 ★★★★★
()
Ответ на: комментарий от tailgunner

Что такое «более-менее детерминированная программа» и чем она отличается от просто «детерминированной»?

Более-менее детерминированная = детерминированная, если железо, компилятор и ОС полностью соответствуют спецификации.

monk ★★★★★
()
Ответ на: комментарий от monk

А отсутствие STL в стандарте повлиляло бы благоприятно на взаимодействие между Qt и VTK? :)

vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 1)
Ответ на: комментарий от eao197

У вас вот GLib в стандарте C2018 (да и сам оный стандарт в наличии)

И стандарт и GLib приведены в качестве аналогии. Или, по-Вашему, поговорка «мне это нужно как рыбе зонтик» подразумевает, что у рыбы есть зонтик?

monk ★★★★★
()
Ответ на: комментарий от monk

На С++ единственным вариантом, дающим более-менее детерминированную программу был catch(...) на каждой функции.

Что такое «более-менее детерминированная программа» и чем она отличается от просто «детерминированной»?

Более-менее детерминированная = детерминированная, если железо, компилятор и ОС полностью соответствуют спецификации.

Какая-то бессмыслица. Не говоря уже о том, что ни железо, ни компилятор, ни ОС никогда не соответствуют спецификации.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Не говоря уже о том, что ни железо, ни компилятор, ни ОС никогда не соответствуют спецификации.

Поэтому «более-менее». Полностью детерминированное поведение может быть только у аппаратно-программного комплекса.

monk ★★★★★
()
Ответ на: комментарий от monk

Я бы спросил, что в твоем понимании «детерминированное поведение», но подозреваю, что услышу очередную псевдоакадемическую трескотню.

tailgunner ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.