Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Коды завершения функции
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2, 3
ViKo
Иногда приходится придумывать некие коды, информирующие о той или иной ошибке при выходе из функции. К EXIT_SUCCESS и EXIT_FAILURE добавляются дополнительные. Не задавались ли вы целью привести коды в систему, чтобы пользоваться во всех случаях? Если да, поделитесь, пожалуйста идеями.
twix
...
arhiv6
Например, есть стандартные системные наборы кодов ошибок: windows, linux.
ViKo
Хорошие коды. Но для встроенной программы избыточны. Я предполагаю использовать максимум 8, и то не знаю, зачем мне столько. Есть у кубовского HAL 4 значения.
Arlleex
Я обычно пишу модульно. То есть есть драйвер, допустим, EEPROM-памяти. Он оформлен парой файлов EEPROM.c и EERPOM.h.
Ну и для каждого драйвера свои сигнатуры завершения функций.
Код
unsigned int ReturnValue = EEPROM_LoadParameters(&EEPROM);
if(ReturnValue == EEPROM_LOAD_ERROR_CRC)
  printf("WARNING! The EEPROM checksum does not match!\n\n\r");
else if(ReturnValue == EEPROM_LOAD_ERROR_ID)
  printf("WARNING! Installed someone else's EEPROM. Read and write operations will be invalid!\n\n\r");

В файле EEPROM.h при этом где-то в самом верху:
Код
#define EEPROM_LOAD_OK        0
#define EEPROM_LOAD_ERROR_CRC 1
#define EEPROM_LOAD_ERROR_ID  2

Но еще лучше сделать их не #define-ми, а enum-ами. В отладчике проще жить станет.

Ну а вот так, допустим, у меня выглядит заголовочный файл драйвера обмена:
CODE
#ifndef _EXCHANGE_H_
#define _EXCHANGE_H_

#define EXCHANGE_RECEIVE_BUFFER_SIZE 32

#define EXCHANGE_RECEIVE_OK 0
#define EXCHANGE_RECEIVE_ERROR 1

#define EXCHANGE_TRANSMIT_OK 0
#define EXCHANGE_TRANSMIT_ERROR 1

#define EXCHANGE_MESSAGE_HANDLING_OK 0
#define EXCHANGE_MESSAGE_HANDLING_ERROR 1

// структура дескриптора транзакций
typedef struct
{
void *Data;
volatile unsigned int Size;
}TExchangeDescriptor;

// структура принимаемых сообщений
typedef struct
{
#define EXCHANGE_RECEIVE_COMMAND_SYSTEM_RESET 0x12345678
unsigned int Command;
}TExchangeReceiveMessage;

// функция приема данных по внешнему каналу обмена
unsigned int EXCHANGE_ReceiveData(TExchangeDescriptor *ExchangeRxDescriptor, unsigned int Timeout);
// функция отправки данных по внешнему каналу обмена
unsigned int EXCHANGE_TransmitData(TExchangeDescriptor *ExchangeTxDescriptor);
// функция обработки принятых сообщений
unsigned int EXCHANGE_ReceiveMessageHandler(TExchangeReceiveMessage *ExchangeReceiveMessage);

#endif

Я обычно в коде логгирую все исключительные ситуации или просто поведение системы в критических участках или интересующих меня местах, поэтому в коде довольно просто писать лог (см. первый блок кода). Но это все дело вкуса, ИМХО.
ViKo
Меня немного смущает, что имя тип возвращаемого кода выглядит "солиднее" имени самой функции.
fpgaConfigRetcode_t Fpga_config(void)

В HAL имеется следующее:
typedef enum
{
HAL_OK = 0x00U,
HAL_ERROR = 0x01U,
HAL_BUSY = 0x02U,
HAL_TIMEOUT = 0x03U
} HAL_StatusTypeDef;
ViKo
Ну, вот такой набор прикинул, скомпилировал из разных источников. Годится?
typedef enum {
SUCCESS_OK, // 0
ERROR_GENERAL_FAILURE, // 1 _UNSPECIFIED
ERROR_INVALID_FUNCTION, // _INVALID_HANDLE, _NOT_IMPLEMENTED
ERROR_INVALID_PARAMETER, // _INVALID_ARGUMENT, _BAD_COMMAND
ERROR_NOT_FOUND, // _FILE, _PATH
ERROR_DEVICE_FAILED, // _DEVICE_NOT_EXIST
ERROR_INVALID_ACCESS, // _ACCESS_DENIED, _LOCK
ERROR_NOT_READY, // _BUSY, _LOCK
ERROR_TIMEOUT,
ERROR_MEMORY, // _OUT_OF_MEMORY, _BUFFER_EXCEEDED
ERROR_POINTER,
ERROR_INVALID_DATA, // _READ_FAULT
ERROR_WRITE_FAULT,
ERROR_PROTECT, // _WRITE_PROTECT
ERROR_VERIFY, // _INVALID_CRC, _INVALID_PASSWORD
ERROR_UNEXPECTED // _ABORT
}
haker_fox
QUOTE (ViKo @ Apr 24 2018, 17:47) *
Ну, вот такой набор прикинул, скомпилировал из разных источников. Годится?

Всё зависит от вашей задачи, если вам хватает, то годится. Посмотрел свои настройки в текущем проекте, большая часть совпадает. Но вот для примера, что у меня
CODE
enum TRetVal {
    /* Common result values */
    rvOK = 0x00,        // Операция завершена без ошибок
    rvFAILED = 0x01,        // Операция завершена с ошибкой (общая ошибка)
    rvCRC_FAILED = 0x02,        // Подсчитанная КС неверна
    rvSETTING_ERROR = 0x03,     // Параметры настроек заданы неверно
    rvTIME_OUT = 0x05,      // Операция завершена с таймаутом
    rvUSER_CANCEL = 0x06,       // Выполнение операции прервано пользователем
    rvPARAM_INCORRECT = 0x0b, /** В функцию переданы неверные параметры */
    rvVIRT_FUNC = 0x0c, /** Функция виртуальная, нет реализации */
    rvNULL_POINTER = 0x0d, /** Попытка обратиться по нулевому указателю */
    rvBUSY = 0x0f, /** Процесс занят */
    rvNOT_CONNECTED = 0x11, /* Соединение не установлено */
    rvOUT_OF_MEMORY = 0x12, /* Закончилась память в куче */

    /*CIRCLE BUFFER*/
    rvBUFFER_OVERFLOW = 0x57, /** Переполнение буфера */
    rvBUFFER_EMPTY = 0x58, /** Буфер данных пуст */
    rvBUFFER_FULL = 0x59, /** Буфер данных заполнен */

    /* Measure core */
    rvOFFSET_ERROR = 0x60, /** Погрешность смещения в одном из токовых каналов */
    rvCANT_CALIBRATE = 0x61, /** Невозможно откалибровать */
    rvNOT_CALIBRATED = 0x62,        // Прибор не откалиброван
    rvALRDY_RUN = 0x63, /** Сбор данных уже запущен */
    rvALRDY_STOPPED = 0x64, /** Сбор данных уже остановлен */

    /* Non-Volatile Memory */
    rvDISK_WRITE_ERROR = 0x70, /** Ошибка записи в микросхему памяти */
    rvDISK_NOT_FOUND = 0x71, /** Не найдена микросхема памяти */

    /* Drivers */
    rvCLOSE = 0x80, /* Устройство закрыто */
    rvOPEN_ERROR = 0x81, /* Ошибка открытия драйвера, например не можем считать ID-микросхемы*/
};

И всё равно не редки ситуации, когда выясняется, что какому-то уникальному модулю нужен свой код ошибки, которого ещё нет. И приходится добавлять. Кстати, у меня ещё вопрос: а как по возвращаемому значению идентифицировать функцию, где произошла ошибка? Так сказать "размотать стек"?
ViKo
Цитата(haker_fox @ Apr 24 2018, 13:03) *
Всё зависит от вашей задачи, если вам хватает, то годится. Посмотрел свои настройки в текущем проекте, большая часть совпадает. Но вот для примера, что у меня

И всё равно не редки ситуации, когда выясняется, что какому-то уникальному модулю нужен свой код ошибки, которого ещё нет. И приходится добавлять. Кстати, у меня ещё вопрос: а как по возвращаемому значению идентифицировать функцию, где произошла ошибка? Так сказать "размотать стек"?

Спасибо, изучу. Идентифицировать буду сразу по возвращению из вызываемой функции, не дожидаясь завершения работы вызывающей функции.
Мне столько кодов не нужно. А если случится непредвиденная ошибка, можно выдать код из наиболее подходящих, или unspecified.
one_eight_seven
Цитата
Ну, вот такой набор прикинул, скомпилировал из разных источников. Годится?

Если пишете для себя - делайте как угодно. Если есть хоть малейшая вероятность, что с вашим кодом будут работать другие люди, то лучше возьмите любой из стандартов, таким, какой он есть, полностью и без самодельных улучшений.
ViKo
Цитата(one_eight_seven @ Apr 24 2018, 13:19) *
Если пишете для себя - делайте как угодно. Если есть хоть малейшая вероятность, что с вашим кодом будут работать другие люди, то лучше возьмите любой из стандартов, таким, какой он есть, полностью и без самодельных улучшений.

Я всегда делаю для себя. Но так, чтобы другим было не стыдно показать. biggrin.gif
Писал выше, мне много кодов не надо. Сначала хотел 4, потом 8, остановлюсь на 16. Полбайта займет, цэ гарно.
one_eight_seven
Цитата
Я всегда делаю для себя. Но так, чтобы другим было не стыдно показать. biggrin.gif

То, что вы для себя скомпилировали - совсем не стыдно. Просто при передаче кода другим людям хорошо использовать стандартные библиотеки - эти самые другие люди не изучают то, что не надо изучать, и даже не задумываются об этом - они просто видят знакомое, и работают без лишних затрат времени.
ViKo
Э, если бы работа в группе заключалась в использовании только стандартных конструкций, сколько бы нервов было спасено. Но это - утопия, пмсм.
Kabdim
Цитата(haker_fox @ Apr 24 2018, 13:03) *
Кстати, у меня ещё вопрос: а как по возвращаемому значению идентифицировать функцию, где произошла ошибка? Так сказать "размотать стек"?

Возвращать PC/LR и по мап файлу смотреть что откуда?
HardEgor
Цитата(ViKo @ Apr 24 2018, 12:26) *
Иногда приходится придумывать некие коды, информирующие о той или иной ошибке при выходе из функции. К EXIT_SUCCESS и EXIT_FAILURE добавляются дополнительные. Не задавались ли вы целью привести коды в систему, чтобы пользоваться во всех случаях? Если да, поделитесь, пожалуйста идеями.

Идея одна - у всех функций коды разные. Тем более функции живут на разных уровнях иерархии. Группировать смысла немного.
Поэтому есть 0 = SUCCESS, остальные коды пишутся и обзываются по порядку появления в функции.
Название формирую из уровня иерархии, например HAL_ плюс библиотека _UART и сокращенное название. Сокращенные названия можно брать из стандартных систем, типа Windows/UNIX
haker_fox
QUOTE (Kabdim @ Apr 24 2018, 18:54) *
Возвращать PC/LR и по мап файлу смотреть что откуда?

Тогда функции должны возращать результаты в виде структур, где, собственно говоря, код завершения, и некая служебная информация.
Kabdim
У вас в чипе 4Гб памяти? Но в общем, если не паковать - да, структура, так будет проще. Насколько я помню функция может использовать до 4 32битных регистров для возвращения значения. В функциональном мире вроде из функций обычно возвращают Result<T, E>.
k155la3
Цитата(ViKo @ Apr 24 2018, 08:26) *
Иногда приходится придумывать некие коды, информирующие о той или иной ошибке при выходе из функции. . . .

Я использую "двуполярный" (положительный и отрицательный) enum.
Критичные ошибки - минус, ноль и плюс - без ошибок и некритичные.
Использую также "битовую" структуру. Взведенный старший бит - флаг наличия ошибки.
Для возврата ошибок через несколько уровней вызова, без использования try-catch,
самый "нижний" код ошибки транслируется "верхними" ф-ми с умножением на 10.
(по разрядности полученной ошибки можно судить с какого уровня "прилетело").
jcxz
Цитата(Kabdim @ Apr 24 2018, 17:39) *
Насколько я помню функция может использовать до 4 32битных регистров для возвращения значения.

Это в каком компиляторе??

ЗЫ: Имхо - для таких тем нужно завести особую ветку форума. Озаглавить её "Конструирование сферических коней в вакууме". И разрешить вход только истинным кавалеристам. cool.gif
ViKo
Из функции можно возвратить структуру, в любом правильном компиляторе. Не предлагаю, но сообщаю.
jcxz
Цитата(ViKo @ Apr 24 2018, 21:39) *
Из функции можно возвратить структуру, в любом правильном компиляторе. Не предлагаю, но сообщаю.

Мне это известно. Только я всегда думал, что размер структуры в этом случае ограничен sizeof(int)*2. По-крайней мере в IAR for ARM.
Может где-то по-другому?
AlexandrY
Цитата(ViKo @ Apr 24 2018, 21:39) *
Из функции можно возвратить структуру, в любом правильном компиляторе. Не предлагаю, но сообщаю.

Ща модно говорить - объект. Объект ошибки.
Слово "сруктура" непроизвольно выдает склонность к ископаемым языкам. biggrin.gif
ViKo
Цитата(AlexandrY @ Apr 25 2018, 08:57) *
Ща модно говорить - объект. Объект ошибки.
Слово "сруктура" непроизвольно выдает склонность к ископаемым языкам. biggrin.gif

Действия и поступки структура и объект - одно и то же (, Айсман)!
AlexandrY
Цитата(ViKo @ Apr 25 2018, 09:08) *
Действия и поступки структура и объект - одно и то же (, Айсман)!

Дело не в семантике.
Язык определяет сознание
Поэтому от "структур" уже время отказаться. laughing.gif
ViKo
А как насчет высказывания jcxz?
Цитата
Только я всегда думал, что размер структуры в этом случае ограничен sizeof(int)*2. По-крайней мере в IAR for ARM.

Я думаю, он нагло ошибается. blink.gif

Цитата(AlexandrY @ Apr 25 2018, 09:12) *
Дело не в семантике.
Поэтому от "структур" уже время отказаться. laughing.gif

"В свое время мы поговорим и об этом." biggrin.gif
jcxz
Цитата(ViKo @ Apr 25 2018, 09:23) *
Я думаю, он нагло ошибается. blink.gif

Может иногда всё-таки лучше почитать мануал?
Код
If the function returns a structure larger than 32 bits, the memory location where the
structure is to be stored is passed as an extra parameter. Notice that it is always
treated as the first parameter.
это о возврате структур.

Код
The registers available for returning values are R0 and R0:R1.
...
long long and double-precision (64-bit) return values: R0:R1
А это - о том как всё-таки можно вернуть структуру размером sizeof(int)*2 в двух регистрах.
ViKo
Первая цитата не показывает, что размер структуры ограничен двумя словами.
Вторая цитата не содержит слова "структура".
"Об чем вы, дядя Сидор?"
Kabdim
Цитата(jcxz @ Apr 24 2018, 19:28) *
Это в каком компиляторе??
...
Только я всегда думал, что размер структуры в этом случае ограничен sizeof(int)*2.

Вы правы, я неправильно запомнил. Хотя мне казалось логичным сделать Argument = result = scratch, но инфоцентр 5.1.1 Core registers определяет по другому. И по передаче структур больше слова, тоже. Блин на х86 это сделано разумнее.
haker_fox
QUOTE (Kabdim @ Apr 24 2018, 22:39) *
У вас в чипе 4Гб памяти?

ОЗУ? 140 кБ встроенной, и снаружи 32 Мб.

QUOTE (ViKo @ Apr 25 2018, 02:39) *
Из функции можно возвратить структуру, в любом правильном компиляторе. Не предлагаю, но сообщаю.

Да, это верно. Возвращаем,и даже не задумываемся.

QUOTE (jcxz @ Apr 25 2018, 02:44) *
Мне это известно. Только я всегда думал, что размер структуры в этом случае ограничен sizeof(int)*2. По-крайней мере в IAR for ARM.
Может где-то по-другому?

Не совсем понял, о чём вы?
jcxz
Цитата(ViKo @ Apr 25 2018, 10:33) *
Первая цитата не показывает, что размер структуры ограничен двумя словами.
Вторая цитата не содержит слова "структура".

Если не умеете читать и понимать даже выдержки из даташита - Ваши проблемы.
Может приведёте какие-то аргументы? Я аргументы привёл, от Вас - только трёп. laughing.gif

Цитата(haker_fox @ Apr 25 2018, 10:38) *
Не совсем понял, о чём вы?

О том, что компилятор IAR (for ARM) позволяет использовать для возвращаемых значений до двух регистров (R0,R1).
Если кто-то знает другое (или про компилятор использующий большее число регистров) - плиз приведите аргументы.
Kabdim
Цитата(haker_fox @ Apr 25 2018, 10:38) *
ОЗУ? 140 кБ встроенной, и снаружи 32 Мб.

Вряд ли эта ОЗУ вся забита кодом, т.е. реально упаковать код ошибки + pc в 32битное слово, или +lr и возвращать 64 бита.
ViKo
Цитата(jcxz @ Apr 25 2018, 10:41) *
Если не умеете читать и понимать даже выдержки из даташита - Ваши проблемы.
Может приведёте какие-то аргументы? Я аргументы привёл, от Вас - только трёп. laughing.gif

О том, что компилятор IAR (for ARM) позволяет использовать для возвращаемых значений до двух регистров (R0,R1).
Если кто-то знает другое (или про компилятор использующий большее число регистров) - плиз приведите аргументы.

Цитата
5.4 Result Return
The manner in which a result is returned from a function is determined by the type of that result.
For the base standard:
 A Half-precision Floating Point Type is converted to single precision and returned in r0.
 A Fundamental Data Type that is smaller than 4 bytes is zero- or sign-extended to a word and returned in r0.
 A word-sized Fundamental Data Type (e.g., int, float) is returned in r0.
 A double-word sized Fundamental Data Type (e.g., long long, double and 64-bit containerized vectors) is
returned in r0 and r1.
 A 128-bit containerized vector is returned in r0-r3.
 A Composite Type not larger than 4 bytes is returned in r0. The format is as if the result had been stored in
memory at a word-aligned address and then loaded into r0 with an LDR instruction. Any bits in r0 that lie
outside the bounds of the result have unspecified values.
 A Composite Type larger than 4 bytes, or whose size cannot be determined statically by both caller and
callee, is stored in memory at an address passed as an extra argument when the function was called (§5.5,
rule A.4). The memory to be used for the result may be modified at any point during the function call.
jcxz
И откуда сиё взято? В "IAR C/C++ Development Guide" поиск даже просто любого из слов "containerized" или "128-bit" - Not found.

Цитата(Kabdim @ Apr 25 2018, 10:58) *
Вряд ли эта ОЗУ вся забита кодом, т.е. реально упаковать код ошибки + pc в 32битное слово, или +lr и возвращать 64 бита.

Не понятна эта фраза. wacko.gif
Вы предлагаете к адресу возврата прибавлять некое число, которое и является результатом? Тогда после каждой точки вызова этой функции придётся располагать таблицу из N*2 инструкций B (где N - максимальное возвращаемое значение). И на си такое будет сложно проделать.
ViKo
http://infocenter.arm.com/help/topic/com.a...0042F_aapcs.pdf
Я, правда, процитировал предыдущую версию. Там есть небольшое отличие, для данной темы несущественное.
haker_fox
QUOTE (jcxz @ Apr 25 2018, 15:41) *
Если кто-то знает другое (или про компилятор использующий большее число регистров) - плиз приведите аргументы.

Я вообще никогда не задумывался над этим. Возвращал стурктуры, и всё. Методами класса. Т.к. использую Си++, но это наверно сути не меняет. Возвращал структуры до 100 байт размером. Думаю, что если есть ограничение, компилятор какую-то подстановку выполняет. Но разве это имеет значение?

QUOTE (Kabdim @ Apr 25 2018, 15:58) *
Вряд ли эта ОЗУ вся забита кодом, т.е. реально упаковать код ошибки + pc в 32битное слово, или +lr и возвращать 64 бита.

По-прежнему не понимаю вас)
Вот пример возвращаемой структуры:
CODE
typedef struct FuncResult {
    CodeResult result;
    uint32_t lrReg;
    uint32_t pcReg;
};

Правильно?
Kabdim
Цитата(jcxz @ Apr 25 2018, 11:38) *
Не понятна эта фраза. wacko.gif

Просто битовая упаковка структуры.
Цитата(haker_fox @ Apr 25 2018, 11:51) *
По-прежнему не понимаю вас)
Вот пример возвращаемой структуры:
Код
typedef struct FuncResult {
    CodeResult result;
    uint32_t lrReg;
    uint32_t pcReg;
};

Правильно?

В стартовом варианте, до уапковки - да. Только я бы добавил еще bool для детектирование ошибка/без ошибок. Без ошибки значения структуры нужно использовать для возвращения собственно результата.
Т.е. скорее
Код
template<class T, class E>struct Result {
    bool is_valid;
    union {
        T t;
        struct {
            E e;
            uint32_t lrReg;
            uint32_t pcReg;
        }
    }
}
jcxz
Цитата(ViKo @ Apr 25 2018, 11:42) *
Я, правда, процитировал предыдущую версию. Там есть небольшое отличие, для данной темы несущественное.

И что? Я разве отрицал, что возможно возвращать более чем два регистра? Да, раз R0-R3, R12 - scratch registers, то (согласно логике) можно хоть все их использовать для return.
Но мне неизвестен такой компилятор, который так делает. Про него и спрашивал.
Вам такой известен?

Цитата(haker_fox @ Apr 25 2018, 11:51) *
Я вообще никогда не задумывался над этим. Возвращал стурктуры, и всё. Методами класса. Т.к. использую Си++, но это наверно сути не меняет. Возвращал структуры до 100 байт размером. Думаю, что если есть ограничение, компилятор какую-то подстановку выполняет. Но разве это имеет значение?

А следует задумываться. Конечно имеет. Такой возврат будет выполняться на стеке. И это место на стеке выделяется вызывающим кодом. В точке вызова. Соответственно - в стеке должно быть достаточно места.
haker_fox
QUOTE (Kabdim @ Apr 25 2018, 16:55) *
Только я бы добавил еще bool для детектирование ошибка/без ошибок.

Я бы добавил в эту структуру конструктор для установки членов структуры в значения по умолчанию. Можно добавить метод isError(), isSuccess() и т.д. и т.п. 1111493779.gif
one_eight_seven
Цитата
Думаю, что если есть ограничение, компилятор какую-то подстановку выполняет. Но разве это имеет значение?

Ну, значение, находящееся в регистрах можно использовать сразу же. Значение, которое сначала сохраняется в память, а потом из неё читается в регистры, чтобы его можно было использовать - запускает как минимум 2 операции работы с памятью, что гораздо медленее, особенно, если у вашей машины нет кэша. Операции с памятью, они, вообще, достаточно дорогие в плане производительности. А, возвращаясь к первоначальному вопросу - возвращению кода ошибки... 2^800 кодов ошибок - это уже слишком sm.gif В этом случае лучше вернуть наличие/отсутствие ошибки через регистр, а остальное поместить в память, и пусть оно (остальное) считывается, только если нужно.
jcxz
Цитата(haker_fox @ Apr 25 2018, 12:03) *
Я бы добавил в эту структуру конструктор для установки членов структуры в значения по умолчанию. Можно добавить метод isError(), isSuccess() и т.д. и т.п. 1111493779.gif

......вот так и рождается калокуб. Когда для записи одного значения в регистр периферии вызывается куча функций и получается монстр..... laughing.gif
Kabdim
Цитата(haker_fox @ Apr 25 2018, 12:03) *
Я бы добавил в эту структуру конструктор для установки членов структуры в значения по умолчанию. Можно добавить метод isError(), isSuccess() и т.д. и т.п. 1111493779.gif

Конечно, а еще макрос unwrap что бы делал ранний возврат из ошибок и насыпать функциональных map, flat_map, filter. Но это уже другой разговор. sm.gif

Цитата(jcxz @ Apr 25 2018, 12:06) *
......вот так и рождается калокуб. Когда для записи одного значения в регистр периферии вызывается куча функций и получается монстр..... laughing.gif

Куб рождается индусами(как минимум в душе) что бы и в каком стиле они не делали. Если делать по уму этот синтаксический сахар оптимизируется до почти нуля.
jcxz
Цитата(one_eight_seven @ Apr 25 2018, 12:06) *
возвращаясь к первоначальному вопросу - возвращению кода ошибки... 2:800 кодов ошибок - это уже слишком sm.gif

Тема изначального вопроса: изобретение сферического коня на все случаи жизни. Наверняка найдётся такой случай который потребует столько значений. А значит и для функции из одной строки возвращающей истина/ложь надо этого коня запрячь. Со всеми вытекающими.

PS: Как показывает практика - универсальные кони нафиг не нужны в реальных проектах. В каждом конкретном случае формат возвращаемых значений следует выбирать наиболее оптимальным для этого конкретного случая. Всё универсальное - неоптимально по определению и годится только для быдлокодерства в ардуино-стиле. laughing.gif
one_eight_seven
Цитата
Всё универсальное - неоптимально по определению и годится только для быдлокодерства в ардуино-стиле.

А если не "универсальное", а "унифицированное"?
Сергей Борщ
QUOTE (haker_fox @ Apr 25 2018, 10:51) *
Вот пример возвращаемой структуры:
CODE
typedef struct FuncResult {
    CodeResult result;
    uint32_t lrReg;
    uint32_t pcReg;
};

Правильно?
Неаккуратненько wink.gif Должно быть как минимум так:
CODE
typedef struct FuncResult {
    CodeResult result;
    uintptr_t lrReg;
    uintptr_t pcReg;
};
AlexandrY
Цитата(haker_fox @ Apr 25 2018, 12:03) *
Я бы добавил в эту структуру конструктор для установки членов структуры в значения по умолчанию. Можно добавить метод isError(), isSuccess() и т.д. и т.п. 1111493779.gif

Как-то мало энтузиазма.
Наверно начать надо было бы с абстрактного синглтона фабрики объектов ошибок.
На фабрике регистрировались бы все заинтересованные сторонние классы которым нужно знать и реагировать на ошибки.
При регистрации классы обменивались бы своими делегатами и получали бы объекты готовых к использованию типизированных ошибок там с сериализацей, потоками, логами, конвертерами и прочей х...
И крышеснос готов. biggrin.gif
haker_fox
QUOTE (jcxz @ Apr 25 2018, 17:06) *
......вот так и рождается калокуб. Когда для записи одного значения в регистр периферии вызывается куча функций и получается монстр..... laughing.gif

Я не знаю, что такое "калокуб", хотя наслышан о нём. А вообще, какая разница у кого что рождается, главное, чтобы у самих всё было замечательно rolleyes.gif

QUOTE (AlexandrY @ Apr 25 2018, 17:32) *
Как-то мало энтузиазма.
Наверно начать надо было бы с абстрактного синглтона фабрики объектов ошибок.
На фабрике регистрировались бы все заинтересованные сторонние классы которым нужно знать и реагировать на ошибки.
При регистрации классы обменивались бы своими делегатами и получали бы объекты готовых к использованию типизированных ошибок там с сериализацей, потоками, логами, конвертерами и прочей х...
И крышеснос готов. biggrin.gif

Ох... житие мое rolleyes.gif
arhiv6
А кто-нибудь использует для обработки ошибок CException или что-нибудь подобное? Вот ещё о нём: Обработка исключений на языке C.
Forger
Цитата(arhiv6 @ Apr 25 2018, 13:43) *
А кто-нибудь использует для обработки ошибок CException или что-нибудь подобное?

Поделюсь своим небольшим опытом ))

В толстых проектах - обязательно С++ и exсeption.
В маленьких и средних тоже С++, но без тяжелых exсeption (отъедает много места у маленьких камней).

Стараюсь всегда избегать функций (в C++ методов), которые помимо основной своей задачи еще и возвращают код ошибки.
Максимум - такая функция возвращает bool. Это дает возможность дать фунции осмысленное имя в соотв. с построением языка носителя - английского.
Это капитально улучшает читаемость кода, т.к. не нужно после возврата из такой функции проводить анализ возвращаемого кода ошибки с монстроподобным switch-case.

Например, нужно дождаться какого-то события (освобождения мьютекса), использую такую конструкцию:
Код
if (someSemaphore.isWaitingDone(100ms))
{
.....
}else...


Если нужно ждать бесконечно, то просто:
Код
someSemaphore.wait();


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

Чем проще входная и выходная часть функции, тем проще ее применять.
Кстати, насчет входной части: если в функцию передается более двух параметров, то такая функция требует перестроения.
В сложных случаях в функцию лучше передавать указатель (а в С++ ссылку) на экземпляр структуры, которую нужно заранее создать и вписать в нее нужные параметры.
Читаемость такого кода значительно выше, чем функция, в которую суют вагон разношерстных параметров и еще эта функция возвращает какой-то код ошибки.
В крайнем случае лучше сделать отдельную функцию для возврата кода ошибки в стиле getLastError, но это анахронический костыль, который лишь немного улучшает ситуацию.
Обычно, если функция может возвращать кучу разных ошибок, то это - неудачная функция и поэтому требует перепроектирования код модуля, где она применяется.
В случаях вынужденного использования чужого кода "as is", такие страшные функции лучше изолировать т. н. "обертками" (в С++ для этого отлично годится понятие класс).

Короче, сложные запутанные куски кода прячьте в простые и однозначные модули, узлы, классы и т. п.
Давайте сущностям (функции, объекты) полные и однозначные имена. Это навык в дальнейшем очень сильно пригодится.


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


зы. недавно в своем "любимом" Keil я перешел на С++11/14 (компилятор v6.10), кстати код получается меньше и быстрее
Можно сказать "пришлось" это сделать, т. к. С++03 (компилятор v5) сильно ограничивает применение чужого кода, который в большинстве своем требует как минимум C++11.
jcxz
Цитата(Forger @ Apr 25 2018, 20:47) *
Это капитально улучшает читаемость кода, т.к. не нужно после возврата из такой функции проводить анализ возвращаемого кода ошибки с монстроподобным switch-case.

Ну да - заменяя на монстроподобный механизм exception.

Цитата(Forger @ Apr 25 2018, 20:47) *
Сейчас остается все меньше и меньше кода на голом С, он явно умирает, равно как и умер в свое время ASM в чистом виде

Сейчас всё меньше и меньше народу пишет на си, всё больше быдлокодят на абдурине. Следуя Вашей логике - так и следует делать.
И все остальные утверждения - по меньшей мере спорны, если не полностью ложны.... laughing.gif
Forger
Цитата(jcxz @ Apr 25 2018, 20:58) *
Ну да - заменяя на монстроподобный механизм exception.

exception - это не замена функции с параметром и последущими switch-case (если функции вложенные, то вообще полный швах - кода много, да толку мало)
это вообще разные вещи и применять их следует в разных ситуациях
Есть неплохие статьи на эту тему: https://habr.com/post/264417/

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


Цитата
всё больше быдлокодят на абдурине. Следуя Вашей логике - так и следует делать.

Я смотрю, ардуинщики для вас - больная тема cranky.gif А быдлокодеры - это вообще отдельная каста "программеров". Приходится с ними часто работать? Тогда сочувствую ((( wacko.gif
Кстати, редкий ардуинщик понимает, что имеет дело с вполне полноценным С++ компилятором под AVR и потому строчит он по сути на голом С.


Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.