Макрос препроцессора GCC и «#pragma GCC unroll»

Есть ли другой механизм, позволяющий препроцессору GCC сделать это:

#define LIMIT  16
#pragma GCC unroll LIMIT
for (size_t ii = 0; ii < LIMIT; ++ii) {
  ...

Этот код вызывает ошибку:

/path/to/my/file.c:100:20 error: 'LIMIT' undeclared (first use in this function)
  100 | #pragma GCC unroll LIMIT
      |                    ^~~~~

В документации gcc сказано, что это необходимо an integer constant expression specifying the unrolling factor. Я считаю, что мой макрос представляет собой «целочисленное константное выражение», но...

Мой компилятор: riscv64-unknown-elf-gcc (g2ee5e430018) 12.2.0.

Работает ли это, если вы используете #pragma GCC unroll 16? А что, если вы используете #pragma GCC unroll (8+8)?

Jonathan Leffler 28.02.2024 05:47

Оба они работают @JonathanLeffler. Я не могу жестко запрограммировать его, потому что он генерирует код разных размеров. Я использую решение, опубликованное ниже. Спасибо!

Lance E.T. Compte 28.02.2024 06:19

Любопытно, что clang на это не жалуется. Хотя он жалуется, если я пишу #pragma GCC unroll gibberish.

Lundin 28.02.2024 08:47

Я бы, наверное, назвал это еще одной ошибкой gcc. И тот, который существует с версии 8, когда, кажется, была введена эта прагма. gcc 8 дает диагностику предоставления целочисленного константного выражения. Он принимает 8+8, но не константу препроцессора, расширяющуюся до целого числа.

Lundin 28.02.2024 08:52

#pragmas не затрагиваются препроцессором.

gulpr 28.02.2024 10:54

См. C11 §6.10.6 Директива #pragma. В сноске говорится: Реализация не обязана выполнять замену макросов в прагмах, но это разрешено, за исключением стандартных прагм (где STDC следует сразу за прагмой). Таким образом, GCC имеет право не пытаться расширять макросы; другие составители имеют право, если они это сделают. Переносимый код не может предполагать, что произойдет расширение макроса. C23 и C18 говорят примерно то же самое.

Jonathan Leffler 28.02.2024 20:45

@JonathanLeffler, это убийственный ответ. Это объясняет, почему GCC не работает, а Clang работает! Спасибо!

Lance E.T. Compte 29.02.2024 00:25
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
7
207
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

const и constexpr (если вы умеете использовать C++), похоже, работают (проверено с помощью gcc 13.2 на https://godbolt.org/).

const int x = 5;
#pragma GCC unroll x
for (std::size_t ii = 0; ii < x; ++ii) {

Это работает! Спасибо! Раскрась меня в недоумении. Я думал, что макрос препроцессора будет рассматриваться как постоянное целое число. Хм....

Lance E.T. Compte 28.02.2024 06:17

Вместо директивы #pragma можно использовать оператор _Pragma. Немного сложно правильно раскрыть аргумент, но это должно работать как для C, так и для C++ (см. пример на godbolt.org):

#define STRING(V) #V
#define MAKE_PRAGMA(S) _Pragma(S)
#define UNROLL(N) MAKE_PRAGMA(STRING(GCC unroll N))

#define LIMIT 16
...
UNROLL(LIMIT)
for (size_t ii = 0; ii < LIMIT; ++ii) {
  ...
}

Expanding on my comment.

Стандарт C11 §6.10.6 Директива #pragma гласит:

Директива предварительной обработки формы

# pragma pp-tokens-opt new-line

где токен предварительной обработки STDC не следует сразу за прагмой в директиве (до любой замены макроса)174) заставляет реализацию вести себя способом, определяемым реализацией. Такое поведение может привести к сбою перевода или к тому, что транслятор или полученная программа будут вести себя несоответствующим образом. Любая такая прагма, не распознаваемая реализацией, игнорируется.

Если токен предварительной обработки STDC сразу следует за pragma в директиве (до любой замены макроса), то в директиве не выполняется замена макроса, и директива должна иметь одну из следующих форм175), значения которых описаны в другом месте:

#pragma STDC FP_CONTRACT on-off-switch
#pragma STDC FENV_ACCESS on-off-switch
#pragma STDC CX_LIMITED_RANGE on-off-switch
on-off-switch: one of
            ON     OFF           DEFAULT

и сноска 174 гласит:

Реализация не обязана выполнять замену макросов в прагмах, но разрешена, за исключением стандартных прагм (где STDC сразу следует за pragma). Если результат замены макроса в нестандартной прагме имеет ту же форму, что и стандартная прагма, поведение по-прежнему определяется реализацией; реализации разрешено вести себя так, как если бы это была стандартная прагма, но это не обязательно.

(Сноска 175 ссылается на текст, резервирующий #pragma STDC … для будущего использования по стандарту.)

Сноска 174 имеет решающее значение. Это означает, что GCC имеет право не предпринимать попытки макроэкспансии; другие составители имеют право, если они это сделают. Оба соответствуют стандарту C.

  • Портативный код не может предполагать, что расширение макроса будет происходить в директиве #pragma.

C23 и C18 говорят примерно одно и то же.

Что вы с этим сделаете, зависит от ваших требований. Однако создание оператора _Pragma (см. §6.10.9 Прагма-оператор ), вероятно, является лучшим (наиболее переносимым и надежным) способом — как предложил Нильсен в своем ответе. Пример в стандарте показывает построение строки с заменой макросов и т.д.

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