Пример использования:
void closefrom (int lowfd);
int main()
{
// expected warning
closefrom(-1);
return 0;
}
В частности: я должен реализовать диагностику (предупреждение компилятора) для вызовов функций. Функция находится в glibc:
void closefrom (int lowfd);
Если lowfd
отрицательный, компилятор должен выдать предупреждение.
Вот некоторая информация о closefrom
:
https://sourceware.org/pipermail/libc-alpha/2021-August/129718.html
Может атрибут функции как-то поможет в этом?
Вы не ожидаете решения, которое будет работать с переменные, переданным foo
, не так ли?
В этом случае, может быть, вместо этого рассмотреть unsigned
?
@KamilCuk, я использую gcc
@ Нил, я не могу реализовать эту функцию. В частности: я должен реализовать диагностику (предупреждение компилятора) для вызовов функций. Функция находится в glibc: void closefrom (int lowfd);
@EugeneSh., да, я хочу выдавать предупреждение только в том случае, если компилятор может вычислить значение (путем оптимизации или если значение постоянно). В противном случае просто используйте функцию без предупреждений.
@levsha Тогда, если вы собираетесь использовать метод, который Эрик дал в ответе, вы получите ошибки компиляции при передаче ему любых переменных.
@EugeneSh., метод Эрика довольно интересный, но мне он не подходит.
Отредактируйте вопрос, чтобы уточнить. «у меня это не работает» — не верное описание проблемы. Покажите желаемое поведение. В вопросе вы указываете «… я должен вынести предупреждение». Что вы имеете в виду под «я»? Вы человек. Чтобы вынести предупреждение, запишите его на листе бумаги и отправьте друзьям по почте. Или своим врагам. Или вы хотите, чтобы что-то в процессе сборки выдавало предупреждение при сборке проекта? Или вы имеете в виду, что пишете или модифицируете компилятор и хотите добавить в компилятор эту функцию предупреждения?…
… Или вы пишете интерфейс библиотеки и хотите сделать что-то, чтобы компилятор выдавал предупреждение, когда ваша подпрограмма вызывается с отрицательным аргументом? Если да, объясните, почему предложенные мной методы недостаточны. Кроме того, веб-поиск closefrom
с помощью glibc ничего не дает. Является ли closefrom
подпрограммой glibc? Где документация на него?
Я думаю, что определение значения переменной во время компиляции в целом, вероятно, неразрешимо. Вы рассматривали стандарт assert
?
@EricPostpischil, прошу прощения за неточное описание проблемы, я просто хотел получить только подсказку сделать задание, а не решение проблемы, поэтому мне показалось, что такого описания проблемы достаточно. Я отредактировал вопрос, надеюсь, что теперь описание проблемы понятно. Вот некоторая информация о closefrom
: sourceware.org/pipermail/libc-alpha/2021-August/129718.html
Вы можете сделать это так, но не делайте этого:
void foo(int x) {}
#define foo(x) foo(((int [(x)+1]){0}, (x)))
int main(void)
{
foo(-1);
return 0;
}
Макрос пытается создать составной литерал, состоящий из массива с (x)+1
элементами. Если x
отрицательное, (x)+1
будет отрицательным или равным нулю, и компилятор сообщит о неправильном размере массива. (Это может потребовать использования переключателей компилятора для отключения расширения массива нулевой длины.) Если x
равно нулю или положительна, составной литерал будет отброшен оператором запятой, а foo
будет вызываться с аргументом x
. (Когда имя макроса используется в своей собственной замене, оно не заменяется снова, поэтому будет вызвана функция foo
.)
Обратите внимание, что возможно переполнение в (x)+1
. Вы можете добавить проверку против INT_MAX
, чтобы справиться с этим.
Для этого требуется, чтобы x
было некоторым выражением времени компиляции, которое подразумевается в вашем вопросе о том, как проверять во время компиляции.
С помощью Clang или GCC вы можете комбинировать стандартный _Static_assert
с нестандартным операторным выражением:
#define foo(x) ({ _Static_assert((x) >= 0, "Argument to foo must be nonnegative."); foo(x); })
Если foo
всегда void
, вы можете просто использовать _Static_assert
с идиомой do … while
, чтобы придать ей форму утверждения, когда добавляется точка с запятой:
#define foo(x) do { _Static_assert((x) >= 0, "Argument to foo must be nonnegative."); foo(x); } while (0)
Если x
может быть чем-то отличным от int
, например, типом с плавающей запятой, вы можете немного поработать над условиями, чтобы решить проблемы, возникающие в тестах и преобразованиях.
Спасибо за ответ, ваш метод довольно интересен, но у меня он не работает. Я отредактировал вопрос, чтобы указать проблему.
want to issue warning only if compiler is able to calculate the value (by optimizations, or if the value is constant). Otherwise just use function without warnin
Короче говоря, с расширениями GNU:
void foo (int lowfd);
#if defined(__GNUC__) && defined(__OPTIMIZE__)
#define curb(expr, msg) \
__extension__({ \
if (__builtin_constant_p(expr)) { \
if (!(expr)) { \
__attribute__((__noinline__, \
__warning__(msg))) void warnit() {__asm__("");}; warnit(); \
} \
} \
})
#else
#define curb(expr, msg) (void)0
#endif
#define foo(x) (curb(x >= 0, "x is lower than 0"), foo(x))
int main()
{
// expected warning
foo(-1);
return 0;
}
У меня есть этот https://gitlab.com/Kamcuk/kamillibc/-/blob/master/libs/curb/src/curb.h#L46 в моем дереве об идее выдачи предупреждения или ошибки, если выражение известно во время компиляции, а если нет, сбой во время выполнения или нет. && defined(__OPTIMIZE__)
кажется, не нужен в этом случае.
Спасибо за ваше решение, оно работает, и я даже понял, как именно. Только я не понимаю, зачем в функции ассемблерная вставка warnit
и почему она нетлайн. Кстати, при компиляции возникает ошибка, связанная с определением функции warnit
внутри расширение, поэтому я просто вынул ее оттуда, потому что мне не нужна переменная msg
, так что задача выполнена.
assembler insert in the function warnit and
Так что это не оптимизировано, __asm__
эффективно запрещает оптимизацию. why it is noinline
По той же причине. Оптимизация функции удаляет потенциальное предупреждение. an error
какая ошибка?
Прошу прощения, ошибся, ошибки компиляции нет.
"Как я могу" - это слишком широкий вопрос. Какой компилятор вы будете использовать?
Maybe attribute
атрибут специфичен для компилятора gcc.