Объединение устаревшего атрибута функции GNU C и C23

Проблема, с которой я столкнулся при использовании приведенного ниже макроса

// Assume that __GNUC__ or __clang__ is defined. 

#if defined(__has_c_attribute)
    #if __has_c_attribute(deprecated)
        #define ATTRIBUTE_DEPRECATED(...)          [[deprecated(__VA_ARGS__)]]
    #endif    /* deprecated */
#else  
    #define ATTRIBUTE_DEPRECATED(...)              __attribute__((deprecated(__VA_ARGS__)))
#endif    /* __has_c_attribute */

в том, что __attribute__((deprecated())) и __attribute__((deprecated)) эквивалентны, а [[deprecated()]] и [[deprecated]] нет.

Блок #else работает корректно при вызове с помощью любого из них:

ATTRIB_DEPRECATED()
ATTRIB_DEPRECATED("privat")

потому что GNU C допускает, чтобы список параметров атрибута был пустым.

Но при компиляции с std=c2x блок #if этого не делает и происходит сбой:

deprecated.c:12:14: error: parentheses must be omitted if attribute argument list is empty

Есть ли способ заставить тот же код работать и с C23?

Еще было бы лучше, если бы я мог написать:

ATTRIB_DEPRECATED

вместо:

ATTRIB_DEPRECATED()

если бы не было аргументов.

Для MRE:

// Assume that __GNUC__ or __clang__ is defined. 

#if defined(__has_c_attribute) 
    #if __has_c_attribute(deprecated)
        #define ATTRIBUTE_DEPRECATED(...)          [[deprecated(__VA_ARGS__)]]
    #endif
#else  
    #define ATTRIBUTE_DEPRECATED(...)              __attribute__((deprecated(__VA_ARGS__)))
#endif    /* __has_c_attribute */

ATTRIBUTE_DEPRECATED() int min(int a, int b)
{
    return a < b ? a : b;
}

int main() {
    return min(10, 20);
}

Приведенный выше код компилировал бы только f __has_c_attribute не был определен.

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

Ответы 2

Ответ принят как подходящий

Я считаю, что для этого вам нужно иметь два отдельных макроса


#if defined(__has_c_attribute) 
    #if __has_c_attribute(deprecated)
        #define ATTRIBUTE_DEPRECATED          [[deprecated]]
        #define ATTRIBUTE_DEPRECATEDR(...)    [[deprecated(#__VA_ARGS__)]]
    #endif
#else  
    #define ATTRIBUTE_DEPRECATED              __attribute__((deprecated))
    #define ATTRIBUTE_DEPRECATEDR(...)        __attribute__((deprecated))
#endif    /* __has_c_attribute */



ATTRIBUTE_DEPRECATEDR(this is test) int min(int a, int b)
{
    return a < b ? a : b;
}

ATTRIBUTE_DEPRECATED int max(int a, int b)
{
    return a > b ? a : b;
}

int main() {
    return min(max(10,20), max(10, 20));
}

https://godbolt.org/z/8arY74Gsd

Просто ВА_ОПТ это.

#define ATTRIBUTE_DEPRECATED(...)  [[deprecated __VA_OPT__( (__VA_ARGS__) )]]

ATTRIBUTE_DEPRECATED()
ATTRIBUTE_DEPRECATED("bla")

Ниже без VA_OPT. Сначала берем код из https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ . Затем мы добавляем некоторый помощник по перегрузке, основанный на возврате ISEMPTY(). Каждая перегрузка просто добавляет аргумент или нет.

#define _ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15
#define HAS_COMMA(...) _ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
#define _TRIGGER_PARENTHESIS_(...) ,
 
#define ISEMPTY(...)                                                    \
_ISEMPTY(                                                               \
          /* test if there is just one argument, eventually an empty    \
             one */                                                     \
          HAS_COMMA(__VA_ARGS__),                                       \
          /* test if _TRIGGER_PARENTHESIS_ together with the argument   \
             adds a comma */                                            \
          HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__),                 \
          /* test if the argument together with a parenthesis           \
             adds a comma */                                            \
          HAS_COMMA(__VA_ARGS__ (/*empty*/)),                           \
          /* test if placing it between _TRIGGER_PARENTHESIS_ and the   \
             parenthesis adds a comma */                                \
          HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__ (/*empty*/))      \
          )

#define PASTE5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
#define _ISEMPTY(_0, _1, _2, _3) HAS_COMMA(PASTE5(_IS_EMPTY_CASE_, _0, _1, _2, _3))
#define _IS_EMPTY_CASE_0001 ,

// -----------------------------

#define CONCAT(a, b)  a##b
#define XCONCAT(a, b)  CONCAT(a, b)

#define ATTRIBUTE_DEPRECATED1()  \
        [[deprecated]]
#define ATTRIBUTE_DEPRECATED0(...)  \
        [[deprecated(__VA_ARGS__)]]
#define ATTRIBUTE_DEPRECATED(...)  \
        XCONCAT(ATTRIBUTE_DEPRECATED, ISEMPTY(__VA_ARGS__))(__VA_ARGS__)


ATTRIBUTE_DEPRECATED()
ATTRIBUTE_DEPRECATED("bla")

Обратите внимание: передача пустого списка () для макроса с помощью (...) технически не соответствует требованиям и нарушает https://port70.net/~nsz/c/c11/n1570.html#6.10.3p4 . Но никого это не волнует.

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