среда, 22 мая 2019 г.

суббота, 18 мая 2019 г.

Именованные параметры на GNU C

Компилируется на диалекте GNU языка С (можно проверить на
https://wandbox.org/ ).

#include <stdio.h>  
#include <stdbool.h>
 
typedef struct {
  bool bIsSolt;
  bool bIsPepper;
  bool bIsPoison;
} SoupParams;

#define GET_OVERRIDE(dummy, ARG_1, ARG_2, ARG_3, ACTION, ...) ACTION

#define PARAM_0(...)
#define PARAM_1(ARG_1)       .ARG_1  
#define PARAM_2(ARG_1, ...)  .ARG_1, PARAM_1(__VA_ARGS__)
#define PARAM_3(ARG_1, ...)  .ARG_1, PARAM_2(__VA_ARGS__)

#define SOUP_PARAMS(...) \
  GET_OVERRIDE("dummy_param", ##__VA_ARGS__, PARAM_3, PARAM_2, PARAM_1, PARAM_0)(__VA_ARGS__)

static int make_soup_raw(const SoupParams *poSoupParams_)
{
  if ( !poSoupParams_ ) { return -1; }

  printf("   poSoupParams_->bIsSolt   = %s\n", poSoupParams_->bIsSolt   ? "true" : "false");
  printf("   poSoupParams_->bIsPepper = %s\n", poSoupParams_->bIsPepper ? "true" : "false");
  printf("   poSoupParams_->bIsPoison = %s\n", poSoupParams_->bIsPoison ? "true" : "false");

  return 0;
}

#define make_soup(...)                                     \
(                                                          \
  {                                                        \
    int nResult = -1;                                      \
    _Pragma("GCC diagnostic push")                         \
    _Pragma("GCC diagnostic ignored \"-Woverride-init\"")  \
    nResult = make_soup_raw(                               \
                            &(SoupParams)                  \
                            {                              \
                               .bIsSolt   = false,         \
                               .bIsPepper = false,         \
                               .bIsPoison = false,         \
                               SOUP_PARAMS(__VA_ARGS__)    \
                             }                             \
                            );                             \
    _Pragma("GCC diagnostic pop")                          \
    nResult;                                               \
  }                                                        \
)

int main(void)
{
  int nResult = 0;
 
  printf("\n make_soup(bIsSolt = true, bIsPoison = true, bIsPepper = true): \n");
  nResult = make_soup(bIsSolt = true, bIsPoison = true, bIsPepper = true);
  printf("   nResult: %d\n", nResult);
  
  printf("\n make_soup(bIsPepper = true, bIsSolt = true): \n");
  nResult = make_soup(bIsPepper = true, bIsSolt = true);
  printf("   nResult: %d\n", nResult);  

  printf("\n make_soup(bIsPoison = false): \n");
  nResult = make_soup(bIsPoison = false);
  printf("   nResult: %d\n", nResult);  
  
  printf("\n make_soup(): \n");
  nResult = make_soup();
  printf("   nResult: %d\n", nResult);    
  
  return 0;  
}

вторник, 1 января 2019 г.

Типовая ошибка при сравнении signed и unsigned int

#include <stdio.h>  
#include <stdint.h>

typedef struct {
    uint32_t iProtocol;
} TCN_BPDU;

#define TCN_BPDU_SIZE    sizeof(TCN_BPDU)
#define SIZE_LLC_HEADER  3

/* парсер TCN BPDU пакета */
static void _parseTcnBpdu(uint8_t *paPktData_, int nSize_)
{
    /*
     В качестве размера nSize_ приходит отрицательное число (-1), signed int.
     Под определением TCN_BPDU_SIZE скрывается результат работы функции sizeof(..),
     то есть 'size_t' - unsigned long int.
     При операции сравнения unsigned long int и signed int, 
     будет приведение signed значения к unsigned значению.
     То есть:
       nSize_ = -1 => nSize_ = (unsigned long int) -1 = 4294967295
     Поэтому, казалось бы:
       if ( nSize_ < TCN_BPDU_SIZE ) { return; }  => if ( -1 < 4 ) { return; }
     Но фактически:
       if ( nSize_ < TCN_BPDU_SIZE ) { return; } => if ( 4294967295 < 4 ) { return; }; 
     Результат: ЗАЩИТА НЕ ОТРАБОТАЕТ
    */
    if ( nSize_ < TCN_BPDU_SIZE ) {
        printf("THIS IS NOT TCN_BPDU\n");
        return;
    }
    printf("THIS IS TCN_BPDU\n");
}

/* обработчик приема пакета */
static void _receiveHandler(uint8_t *psBufRaw_, int nSize_)
{
    /*
     Мы знаем, что к нам приходит пакет с LLC header-ом,
     поэтому 'смело' смещаем указатель и уменьшаем размер данных
     на размер LLC header-а.
     И совершаем ошибку - так как размер пакета меньше размера LLC header-а,
     получаем отрицательную длину данных.
    */
    _parseTcnBpdu(psBufRaw + SIZE_LLC_HEADER, nSize - SIZE_LLC_HEADER);
}

int main(void)
{
    uint8_t aBuf[] = { 1, 2 };
    _receiveHandler(aBuf, sizeof(aBuf));
    return 0;
}