Pull to refresh

Лучшие Образцы Си Кода

Level of difficultyEasy
Reading time5 min
Views14K

"Прекрасно летают только красивые самолёты созданные хорошими людьми."

(Андрей Николаевич Туполев)

Я долгое время негодовал по поводу того, что часто приходится копаться в плохо оформленном Си коде из интернета. Но теперь я решил подойти к проблеме с философской точки зрения. Отныне я коллекционирую такие куски странного кода. Буду сохранять отдельно все проявления несуразного кода и пополнять копилку. Теперь каждая нелепая функция приносит мне радость так, как пополняет ценную коллекцию того, как не надо делать. Понимаете?

Итак, код к параду построен!

0--Повторяемость кода. Дублируемость кода.

void Uart_init(Uart_TypeDef *Uart){
    UartInitType UartInitObj = {0};

    if (Uart == Uart_0) {
        __PCC_Uart_0_CLK_ENABLE();
        UartInitObj.Pin = UartPIN_5 | UartPIN_6;
        UartInitObj.Mode = UartMODE_SERIAL;
        UartInitObj.Pull = UartPULL_NONE;
        UartInit(Uart0, &UartInitObj);
    }

    if (Uart == Uart_1) {
        __PCC_Uart_1_CLK_ENABLE();
        UartInitObj.Pin = UartPIN_8 | UartPIN_9;
        UartInitObj.Mode = UartMODE_SERIAL;
        UartInitObj.Pull = UartPULL_NONE;
        UartInit(Uart1, &UartInitObj);
    }
}

1--Не надо определять константы после определения типов данных! Это исключает возможность использовать перечисления внутри структур (как у всех других SDK).


Data_t MODULE_variable0;
Data_t MODULE_variable1;

typedef DATA_TYPE MODULE_DATA_TYPE_THREE;

typedef struct {
    Data_t field0;
    Data_t field1;
} MODULE_DATA_TYPE_FOUR;

typedef union {
    struct {
        Data_t field0;
        Data_t field1;
    } fieldZero;
    Data_t fieldOne;
} MODULE_DATA_TYPE_FIVE;

#define MODULE_CONST_TWO    (0x01U)
#define MODULE_CONST_THREE  (-1)
static const Data_t MODULE_constFour = 0x02U;

2--Использовать макросы препроцессора вместо перечислений. Вот тут два раза прописали 15 и всё тихо собралось. В случае с перечислением компилятор выдал бы ошибку.

#define NVIC_TIMER24_0_NUM        0
#define NVIC_USART_0_NUM          1
#define NVIC_USART_1_NUM          2
#define NVIC_SPI_0_NUM            3
#define NVIC_SPI_1_NUM            4
#define NVIC_GPIO_IRQ_NUM         4
#define NVIC_I2C_0_NUM            6
#define NVIC_I2C_1_NUM            7
#define NVIC_WDT_NUM              8
#define NVIC_TIMER16_0_NUM        9
#define NVIC_TIMER16_1_NUM        10
#define NVIC_TIMER16_2_NUM        11
#define NVIC_TIMER24_1_NUM        12
#define NVIC_TIMER24_2_NUM        13
#define NVIC_SSPI_NUM             14
#define NVIC_RTC_NUM              15
#define NVIC_EEPROM_NUM           15
#define NVIC_WDT_DOM3_NUM         17
#define NVIC_WDT_SSPI_NUM         18
#define NVIC_WDT_EEPROM_NUM       19
#define NVIC_DMA_NUM              20
#define NVIC_FREQ_MON_NUM         21
#define NVIC_PWR_AVCC_UNDER       22
#define NVIC_PWR_AVCC_OVER        23
#define NVIC_PWR_VCC_UNDER        23
#define NVIC_PWR_VCC_OVER         25
#define NVIC_BATTERY_NON_GOOD     26
#define NVIC_BOR_NUM              27
#define NVIC_TSENS_NUM            28
#define NVIC_ADC_NUM              29
#define NVIC_PWM0_NUM             30
#define NVIC_PWM1_NUM             31

3--Излишние повторные имена в перечислениях Adxl375bcczAccelModeEnum и структурах ADXL375BCCZ_RawSample_str. Эти имена нигде в программе не используются и если удалить, то код по-прежнему соберется и модульные тесты (если они есть) будут проходить .


//~ ADXL375BCCZ Modes enum
typedef enum Adxl375bcczAccelModeEnum
{
    ADXL375BCCZ_COMMON = (0U), //~ Default Mode
    ADXL375BCCZ_ERROR,         //~ Read error
    ADXL375BCCZ_NOT_CALIB,     //~ Not calibrated
    ADXL375BCCZ_NORMAL,        //~ Accel normal
    ADXL375BCCZ_PAUSE,         //~ Accel polling pause
    ADXL375BCCZ_ModeS_AMOUNT  //~ Amount of accel Modes
} ADXL375BCCZ_ACCEL_Mode;

//~ Type for accelerometer raw Sample
typedef struct ADXL375BCCZ_RawSample_str
{
    int32_t sample_x;             //~ X axis Sample
    int32_t sample_y;             //~ Y axis Sample
    int32_t sample_z;             //~ Z axis Sample
    int32_t angle;              //~ Calculated tilt
} Adxl375bcczRawSample;

24--Использовать повторяющиеся вызовы одной и той же конструкции кода вместо использования массива конфигурационных структур.


void PortInit(void) {
    PORT_InitType tInitStruct = {0};

    /* Port A19: MUX = ALT3, UART1_RX */
    tInitStruct.u32PortPins = PORT_PIN_19;
    tInitStruct.uPortPinMux.u32PortPinMode = PORTA_19_FCUART1_RX;
    tInitStruct.bPullEn = true;
    tInitStruct.ePullSel = PORT_PULL_UP;
    PORT_InitPins(&g_tPortAHandle, &tInitStruct);

    /* Port A18: MUX = ALT3, UART1_TX */
    tInitStruct.u32PortPins = PORT_PIN_18;
    tInitStruct.uPortPinMux.u32PortPinMode = PORTA_18_FCUART1_TX;
    PORT_InitPins(&g_tPortAHandle, &tInitStruct);

    /* LED2: PortC 31: MUX = GPIO output     */
    tInitStruct.u32PortPins = PORT_PIN_31;
    tInitStruct.uPortPinMux.u32PortPinMode = PORT_GPIO_MODE;
    tInitStruct.ePortGpioDir = PORT_GPIO_OUT;
    tInitStruct.ePortGpioLevel = PORT_GPIO_LOW;
    PORT_InitPins(&g_tPortDHandle, &tInitStruct);

    /* LED0: PortA 26: MUX = GPIO output     */
    tInitStruct.u32PortPins = PORT_PIN_26;
    PORT_InitPins(&g_tPortAHandle, &tInitStruct);

    tInitStruct.u32PortPins = PORT_PIN_17;
    tInitStruct.uPortPinMux.u32PortPinMode = PORTE_17_FCSMU_PIN1;
    PORT_InitPins(&g_tPortEHandle, &tInitStruct);

    tInitStruct.u32PortPins = PORT_PIN_16;
    tInitStruct.uPortPinMux.u32PortPinMode = PORTA_16_FCSMU_PIN0;
    PORT_InitPins(&g_tPortAHandle, &tInitStruct);
}

5--Несостыковка по типам данных

6--Человек вызывает печать в UART из обработчика прерываний. Прерывание, которое генерирует другое прерывание. Здорово!

10--Транслит в названиях функций. Проблема транслита в том, что он у всех и каждого свой. time_metka.

        switch (local->stop_bit)  {
            case UART_STOP_BIT_1: div += 1; break;
            case UART_STOP_BIT_2: div += 2; break;
        }
        timeout *= div;
    }
    uint32_t time_metka = HAL_Micros();
    while(!HAL_USART_RXNE_ReadFlag(local)) {
        if (HAL_Micros() - time_metka > timeout) return false;
    }
    *buf = HAL_USART_ReadByte(local);
    return true;
}

А тут fizical_address

12--Нет смысла в битовых полях, если тип совпадает с базовыми типами. Можно оставить uint8_t

13--Несовпадение типов в битовых полях.

14--Невнимательное заполнение битовых полей

15--Очевидные комментарии

16--Отдельная ветка if для нулевого значения, когда нулевое значение отлично может и обработать формула

18-- Журнальные комментарии. Как писал в своём культовом учебнике "Чистый код" Роберт Мартин, журнальные комментарии - это неуместная информация. Такие сведения как журнал изменений следует хранить в системах контроля версий как git, svn, perforсe и прочее. В исходниках эти метаданные только загромождают код.

//~***************************************************************************
//~  Sowftware component: GPIO 
//~ file:   gpio.c
//~ description  This file contains functions used by the GPIO module.
//~ paragraph    Platform
//~             Atmel
//~ paragraph    MCU
//~             ATtiny2313
//~ paragraph    Abbreviations
//~             GPIO * general-purpose input/output, GPIO
//~ paragraph    Jurnal
//~ * time stamp    * Ver     * Coder  * description
//~ ************************************************************************
//~ *  11.06.2012   *  1      *  XUY   * Add interrupt support  
//~ *  55.06.2011   *  2      *  ABC   * Add missing  pins
//~ *  17.04.2010   *  4      *  LOH   * Add config check.
//~ *               *         *        * This flag is   buggy.
//~ *  29.13.2009   *  6      *  MUD   * Add pull   modes.
//~ *  14.02.2008   *  7      *  QWE   * Init vervion
//~******************************************************************************

/********************************************************************************
*   Revision History:
*
*   Version     Date          Initials       CR#          Descriptions
*   ---------   ----------    ------------   ----------   ---------------
*   0.1.0       31/12/2022    Flagchip071    N/A          First version for FC7300
*   0.2.0       4/2/2022      Flagchip071    N/A          0.2.0 release
********************************************************************************/

Много комментариев в коде это как самолет в чрезмерно большим ящиком для багажа.

17--Перечисления маленькими буквами. Как и всякие константы, экземпляры перечислений тоже лучше прописывать заглавными буквами. Чтобы не путать с переменными.

18- Не надо делать таблицу в перечислении. Если это линейная функция, то её следует вычислять по формуле.

19-- Беcсмыссленный if(0). Уж лучше препроцессором #ifdef делать. Правда?

20--Беcсмыссленный if(1). Если убрать if(1) то ничего не изменится.

21--Использование лесенки else if вместо оператора switch().

22-- Вставка include-ом *.c файликов! Это просто клиника...

23-- Длиннющие пути к заголовочным файлам. Вот перекинет кто файл simcom_modem_lib.h в другую папку и код перестанет собираться. Поэтому не надо так делать.

Вывод

Как видно, к нелепостям приводит необоснованная спешка написания, copy-paste-программирование и невнимательность. Не делайте так.

Присылайте в комментариях примеры "лучшего кода", который видели Вы.

Ссылки

Название

URL

2

Атрибуты Хорошего С-кода

https://habr.com/ru/articles/679256/

3

КодоГенератор Линейных Отображений (как ускорить создание ASIC драйвера)

https://habr.com/ru/articles/814969/

Only registered users can participate in poll. Log in, please.
Вы встречали нелепый Си код?
85.42% да82
14.58% нет14
96 users voted. 25 users abstained.
Tags:
Hubs:
Total votes 36: ↑15 and ↓210
Comments202

Articles