Проверка значения постоянной переменной во время компиляции - PullRequest
0 голосов
/ 12 декабря 2018

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

#define SPECIFIC_ADDR_IDX 0
#define SPECIFIC_ADDR     8
#define NOT_SPECIFIC_ADDR1 12
#define NOT_SPECIFIC_ADDR2 16

typedef struct _struct_s
{
    const uint16_t addr; // addresses are constant and are not mutable
    uint32_t       val;
} struct_s;

struct_s globArr[] =
{
    {.addr = SPECIFIC_ADDR,      .val = 0},
    {.addr = NOT_SPECIFIC_ADDR1, .val = 0},
    {.addr = NOT_SPECIFIC_ADDR2, .val = 0},
};

// make sure the address at the SPECIFIC_ADDR_IDX is SPECIFIC_ADDR
_Static_assert(globArr[SPECIFIC_ADDR_IDX].addr == SPECIFIC_ADDR, " Illegal!");

Это дает следующую ошибку компиляции:

error: expression in static assertion is not constant
 _Static_assert (globArr[SPECIFIC_ADDR_IDX].addr == SPECIFIC_ADDR, " Illegal!");
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~

addr определяется как const uint16_t, поэтому я подумал, что егозначение известно во время компиляции.

Есть ли эффективный способ выполнить такую ​​проверку во время компиляции?

Уточнение: Я понимаю, что таким образом я могуИспользование _Static_assert, const не делает значение переменной известным во время компиляции.Я спрашиваю, знает ли кто-нибудь какой-нибудь трюк для решения таких вопросов.

Удовлетворительное решение было предложено Камилом Цуком.Инициализация может быть выполнена с указанием индекса:

struct_t globArr[] =
{
    [SPECIFIC_ADDR_IDX] = { .addr = SPECIFIC_ADDR, .val = 0 },
    {.addr = NOT_SPECIFIC_ADDR1, .val = 0},
    {.addr = NOT_SPECIFIC_ADDR2, .val = 0},
};

В этом случае, если будет дополнительная инициализация записи в индексе [SPECIFIC_ADDR_IDX], компилятор выдаст предупреждение (не гарантируется, но большинство компиляторов будет),Просто убедитесь, что скомпилировано с warning = error option ON.

1 Ответ

0 голосов
/ 12 декабря 2018

Вы можете просто указать intex при инициализации:

#define SPECIFIC_ADDR_IDX 0
#define SPECIFIC_ADDR     8
#define NOT_SPECIFIC_ADDR1 12
#define NOT_SPECIFIC_ADDR2 16

typedef struct _struct_s
{
    const uint16_t addr; // addresses are constant and are not mutable
    uint32_t       val;
} struct_t;

struct_t globArr[] =
{
    [SPECIFIC_ADDR_IDX] = { .addr = SPECIFIC_ADDR, .val = 0 },
    {.addr = NOT_SPECIFIC_ADDR1, .val = 0},
    {.addr = NOT_SPECIFIC_ADDR2, .val = 0},
};

В любом случае вам нужно выполнить утверждение во время выполнения, поэтому используйте assert:

void globArr_unittest(void) {
     assert(globArr[SPECIFIC_ADDR_IDX].addr == SPECIFIC_ADDR);
}

static_assert необходимо постоянное выражение.Вы не можете писать статические утверждения на значениях переменных.Даже если вы сделали static const struct_t globArr[] все равно globArr значение не является константным выражением.Язык C не имеет спецификатора constexpr (или consteval), как C ++.Так что, к сожалению, вы не можете сделать это в C.

const это просто модификатор, он говорит, что переменная не может быть изменена через этот дескриптор .const переменные могут быть изменены и не являются неизменяемыми в C.

Это так же, как вы не можете сделать:

#if globArr[SPECIFIC_ADDR_IDX].addr == SPECIFIC_ADDR

то же самое, что вы не можете

static_assert(globArr[SPECIFIC_ADDR_IDX].addr == SPECIFIC_ADDR, "");

Что такое константное выражение, вероятно, хорошо перечислено в cppreference .Результат операторов индекса [] и доступа к элементу . не является константным выражением, поэтому его нельзя использовать в статическом утверждении.

...