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

26/08/2013 - 09:26 Павел Бобков

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


#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]);
   }
}


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

.

Comments   

# Peter 2013-08-27 05:19
Это еще одно "плохое правило программирования"?))
Попробуйте передать свой массивчик bar в какую-то функцию - например, как это бывает - для сортировки или нахождения максимального значения....
Главное - всё скомпилится, никто никого не предупредит о подляне - но посмотрите как это будет работать))
А старый добрый #define - и здесь не подведёт...
# Pashgan 2013-08-27 06:49
Нет, это просто интересный макрос, о котором я недавно узнал.
# Дмитри й 2014-02-28 03:30
Давайте о подляне подробнее. Где и в чем может проявиться?
# Neptun 2013-08-27 13:02
А чем просто sizeof(bar) не понравился?
# Pashgan 2013-08-27 13:31
Просто sizeof даст количество байт, а этот макрос дает количество элементов массива независимо от их типа.

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