Как я могу добавить функцию предупреждения в GCC?

Пример использования:

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

Может атрибут функции как-то поможет в этом?

"Как я могу" - это слишком широкий вопрос. Какой компилятор вы будете использовать? Maybe attribute атрибут специфичен для компилятора gcc.

KamilCuk 08.04.2022 18:39

Вы не ожидаете решения, которое будет работать с переменные, переданным foo, не так ли?

Eugene Sh. 08.04.2022 19:07

В этом случае, может быть, вместо этого рассмотреть unsigned?

Neil 08.04.2022 19:07

@KamilCuk, я использую gcc

levsha 08.04.2022 19:25

@ Нил, я не могу реализовать эту функцию. В частности: я должен реализовать диагностику (предупреждение компилятора) для вызовов функций. Функция находится в glibc: void closefrom (int lowfd);

levsha 08.04.2022 19:32

@EugeneSh., да, я хочу выдавать предупреждение только в том случае, если компилятор может вычислить значение (путем оптимизации или если значение постоянно). В противном случае просто используйте функцию без предупреждений.

levsha 08.04.2022 19:39

@levsha Тогда, если вы собираетесь использовать метод, который Эрик дал в ответе, вы получите ошибки компиляции при передаче ему любых переменных.

Eugene Sh. 08.04.2022 19:41

@EugeneSh., метод Эрика довольно интересный, но мне он не подходит.

levsha 08.04.2022 19:45

Отредактируйте вопрос, чтобы уточнить. «у меня это не работает» — не верное описание проблемы. Покажите желаемое поведение. В вопросе вы указываете «… я должен вынести предупреждение». Что вы имеете в виду под «я»? Вы человек. Чтобы вынести предупреждение, запишите его на листе бумаги и отправьте друзьям по почте. Или своим врагам. Или вы хотите, чтобы что-то в процессе сборки выдавало предупреждение при сборке проекта? Или вы имеете в виду, что пишете или модифицируете компилятор и хотите добавить в компилятор эту функцию предупреждения?…

Eric Postpischil 08.04.2022 20:12

… Или вы пишете интерфейс библиотеки и хотите сделать что-то, чтобы компилятор выдавал предупреждение, когда ваша подпрограмма вызывается с отрицательным аргументом? Если да, объясните, почему предложенные мной методы недостаточны. Кроме того, веб-поиск closefrom с помощью glibc ничего не дает. Является ли closefrom подпрограммой glibc? Где документация на него?

Eric Postpischil 08.04.2022 20:12

Я думаю, что определение значения переменной во время компиляции в целом, вероятно, неразрешимо. Вы рассматривали стандарт assert?

Neil 08.04.2022 20:51

@EricPostpischil, прошу прощения за неточное описание проблемы, я просто хотел получить только подсказку сделать задание, а не решение проблемы, поэтому мне показалось, что такого описания проблемы достаточно. Я отредактировал вопрос, надеюсь, что теперь описание проблемы понятно. Вот некоторая информация о closefrom: sourceware.org/pipermail/libc-alpha/2021-August/129718.html

levsha 08.04.2022 21:00
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
12
94
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете сделать это так, но не делайте этого:

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, например, типом с плавающей запятой, вы можете немного поработать над условиями, чтобы решить проблемы, возникающие в тестах и ​​преобразованиях.

Спасибо за ответ, ваш метод довольно интересен, но у меня он не работает. Я отредактировал вопрос, чтобы указать проблему.

levsha 08.04.2022 19:51
Ответ принят как подходящий

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, так что задача выполнена.

levsha 09.04.2022 17:31
assembler insert in the function warnit and Так что это не оптимизировано, __asm__ эффективно запрещает оптимизацию. why it is noinline По той же причине. Оптимизация функции удаляет потенциальное предупреждение. an error какая ошибка?
KamilCuk 10.04.2022 08:57

Прошу прощения, ошибся, ошибки компиляции нет.

levsha 10.04.2022 17:58

Другие вопросы по теме