Возможны ли проверки времени компиляции для значений параметров в C99 или GCC / Clang? - PullRequest
1 голос
/ 19 марта 2020

У меня есть функция, которая принимает значение длины, которое не должно превышать 32 768. Я хочу проверить это условие во время компиляции, потому что во встроенной системе нет хорошего способа справиться с этой ошибкой. Кроме того, передаваемое значение длины всегда должно быть постоянной времени компиляции, обычно sizeof().

Возможно ли это в C99 или с расширениями GCC / Clang?

Что-то вроде этого, которое, очевидно, делает не компилируется, поскольку len не является интегральной константой.

#include <assert.h>
void fucntion(const uint16_t len)
{
    _Static_assert(len <= 32768, "length parameter too large");
}

Очевидно, что len const здесь не даст желаемого эффекта, а _Static_assert жалуется, что len не является интегральной константой.

Я рассмотрел использование макроса для замены func(), а затем вызвал его, но это имеет два существенных недостатка. Определения макросов не поддерживают такие вещи, как типы или возвращаемые значения, т. Е. Вы не можете сделать

#define bool func(uint16_t len, const void *buffer)

Как указывает Нейт Элдридж, существует расширение G CC (и Clang) это позволяет вам возвращать параметр.

Ответы [ 2 ]

1 голос
/ 19 марта 2020

Вы можете написать утверждение stati c, используя старый трюк с sizeof и отрицательным массивом, и иметь макрос, развернутый на стороне вызова:

void function_real(const uint16_t len);

#define function(len) ((void)sizeof(char[len > 32768 ? -1 : 1]), function_real(len))

В случае, если вы используете C с переменной длиной массивы, sizeof массива будет работать с выражениями, которые не являются целочисленными константными выражениями. Вы можете заставить len быть целочисленным константным выражением, используя старый трюк битового поля для утверждения c. Так похоже, но лучше:

 #define function(len) ((void)sizeof(struct{ int a:len > 32768 ? -1 : 1;}), function_real(len))

Вы можете сделать это как glibc с ­_FORTIFY_SOURCE и использовать оптимизацию компиляции со встроенными функциями gnu и включенной оптимизацией:

void function_real(const uint16_t len);

static inline 
void function(const uint16_t len) {
     if (!__builtin_constant_p(len)) {
            extern __attribute__(( __error__ ( "Och no! len couldn't be evaulated at runtime" ) ))
            void compile_time_error(void);
            compile_time_error();
     } else if (len > 32768) {
            extern __attribute__(( __error__ ( "Och no! len is too small!" ) ))
            void compile_time_error2(void);
            compile_time_error2();
     }

     function_real(len);
}
0 голосов
/ 19 марта 2020

Одна возможность, отмечая некоторые небольшие проблемы:

#define func(len, buffer)                                           \
({                                                                  \
    _Static_assert(len < 32768, "Length exceeds size of EEPROM");   \
    _func(len, buffer);                                             \
})


bool _func(uint16_t len, const void *buffer)
{ }

Благодаря Нейту Элдриджу.

Недостатком этого метода является то, что в среде IDE будет отображаться только информация о макрос при просмотре кода, поэтому, например, вы не получите подсказки о типах параметров. Вы все равно получите обычные проверки и ошибки во время компиляции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...