Макрос для определение количества элементов в массиве

   Существует интересный макрос, который используется для определения количества элементов в объявленном массиве. Его обычное определение выглядит так:

#define N_ELEMENTS(X) (sizeof(X)/sizeof(*(X)))


   Данный макрос удобно применять для перебора всех элементов массива в циклах.

void foo(void)
{
   uint8_t bar[] = {0, 1, 2, 3, 4};
   uint8_t i;

   /* передать каждый элемент массива bar[] */
   for (i = 0; i < N_ELEMENTS(bar); ++i){
      txc(bar[i]);
   }
}


   Это похоже на цикл foreach, который есть в языках PHP и C#. Макрос полезный, но в чем его преимущество перед стандартным подходом?

   Обычно для определения размера массива используется именованная константа. Она же в дальнейшем применяется в качестве ограничителя в циклах. Примерно так:

#define BUF_SIZE (5)

void foo(void)
{
   uint8_t bar[BUF_SIZE] = {0, 1, 2, 3, 4};
   uint8_t i;

   /* передать каждый байт массива bar[] */
   for (i = 0; i < BUF_SIZE; ++i){
      txc(bar[i]);
   }
}


   Если преднамеренно или случайно массив будет объявлен с другим количеством элементов, то цикл выполнится некорректно.

#define BUF_SIZE (5)

void foo(void)
{
   uint8_t bar[BUF_SIZE + 1] = {0, 1, 2, 3, 4, 5};
   uint8_t i;

   /* передать каждый байт массива bar[] */
   for (i = 0; i < BUF_SIZE; ++i){
      txc(bar[i]);
   }
}


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

#define BUF_SIZE (5)

void foo(void)
{
   uint8_t bar[BUF_SIZE + 1] = {0, 1, 2, 3, 4, 5};
   uint8_t i;

   /* передать каждый байт массива bar[] */
   for (i = 0; i < N_ELEMENTS (bar); ++i){
      txc(bar[i]);
   }
}


По материалам блога Найджела Джонса

.

Добавить комментарий

При добавлении в комментарий Си кода, заключайте его между тегами [code] [/code]. Иначе он будет отображаться некорректно.


Защитный код
Обновить