Есть ли способ заменить макросы C для нормального кода C - PullRequest
4 голосов
/ 15 июня 2011

Я хочу запустить инструмент x для файла C и получить код после макроса.(Если мы можем сделать только функции, как макросы, еще лучше).Я знаю о gcc -E, но это также включает все включения в один большой файл.

В основном я хотел бы использовать некоторые макросы C для повторяющегося кода, но не хочу, чтобы окончательный код содержал какие-либо макросы, потому что они не одобрены проектом.

Ответы [ 4 ]

3 голосов
/ 15 июня 2011

Используя выбранный вами язык сценариев, закомментируйте все #include с, затем выполните gcc -E -Wp,-P,-C,-CC foo.c, затем раскомментируйте #include с. Или вы можете заменить #include строкой, которая не начинается с # ... например, include# или @include; возможности безграничны. Подход использования @ вместо # дает вам полный контроль над тем, какие директивы препроцессора делают и не раскрываются ... закодируйте те, которые вы не хотите раскрывать, с помощью @, и тогда скрипт просто запускается gcc -E, а затем изменяется @ на #. Однако я думаю, что было бы лучше сделать это наоборот, используя специальный маркер (например, @), чтобы указать ваши расширяемые макросы. Тогда сценарий превратит ведущие # s во что-то другое (например, HIDE#) и превратит маркер (например, @) в #, запустит gcc -E, затем превратит HIDE# (или что-то еще ) обратно в #.

-Wp указывает параметры препроцессора. -P означает, что не генерирует строковые директивы, -C означает, что не удаляет комментарии, а -CC означает, что не удаляет комментарии, сгенерированные макросами - это означает, что комментарии в макросах, генерирующих код, будут сохранены в выход. Чтобы определить все доступные параметры препроцессора (их очень много, в основном не представляющих интереса), запустите gcc -Wp,--help anyfile.c ... вот что я сделал, чтобы придумать этот ответ (после первого запуска gcc --help, чтобы найти параметр -Wp ). (Знать, как выяснить вещи важнее, чем знать вещи.)

2 голосов
/ 15 июня 2011

Как насчет размещения разделителя в вашем коде сразу после списка #include, чтобы вы могли избавиться от расширений включаемых файлов вручную, но сохранить макрокоманду без изменений после выполнения gcc -E?

Что-то вроде:

#include <one>
#include <two>
void delete_everything_above_and_put_includes_back(); // delimeter
#define MACRO(X) ...
//rest of the code

Я не знаю инструмента, который расширяет макросы, но не расширяет #include s ...

1 голос
/ 15 июня 2011

Я решил добавить еще один ответ, потому что он совершенно другой.

Вместо того, чтобы использовать трюки для расширения макросов в хранилище исходного кода проекта - вы рассматривали возможность использования const переменных и inline функций как альтернативы?

По сути, это причины, по которым макросы "недовольны" в вашем проекте.

Вы должны иметь в виду, что inline - это просто "предложение" (т. Е. Функцияна самом деле может быть не встроенным) и const будет использовать память вместо константного литерала (хорошо, зависит от компилятора, хороший компилятор оптимизирует), но это будет делать две вещи:

  1. Сохранитьваш код в соответствии со стандартами кодирования проекта (что всегда хорошо, по крайней мере политически, если не обязательно технически)
  2. Не потребуются дополнительные скрытые скрипты или действия от вашего имени, чтобы код можно было повторно использовать и поддерживать (Я предполагаю, что вы хотите использовать макросы, чтобы избежать повторяющегося кода, верно?)

ИтакЭп, что в виду, как вариант.

0 голосов
/ 27 августа 2013

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

#define xxPseudoPrototype(RETTYPE, MACRODATA, ARGS) typedef struct { RETTYPE xxmacro__ret__; ARGS } MACRODATA

xxPseudoPrototype(float, xxSUM_data, int x; float y; );
xxSUM_data xxsum;
#define SUM_intfloat(X, Y) ( xxsum = (xxSUM_data){ .x = (X), .y = (Y) }, \
    xxsum.xxmacro__ret__ = xxsum.x + xxsum.y, \
    xxsum.xxmacro__ret__)

Я объяснил детали здесь (в основном, раздел 4, для функционально-подобных макросов):

Функции подделки макросов

  • 1-я строка определяет макрос, который можно использовать для объявления псевдопрототипов для макросов.
  • Во второй строке используется этот макрос, предоставляющий такой псевдопрототип .Он определяет «формальные» параметры нужных типов.По порядку он содержит тип возврата, требуемый для макроса, имя структуры, в которой будут храниться параметры макроса, и, наконец, параметры (с типами!) Макроса.Я предпочитаю называть их псевдопараметрами .
  • 3-я строка является обязательным утверждением, которое делает «реальными» псевдопараметры .Он объявляет структуру, которую необходимо написать.Он определяет структуру, содержащую «реальную» версию псевдопараметров .
  • Наконец, сам макрос определяется как цепочка списков выражений, разделенных запятыми.Первый операнд используется для «загрузки» аргументов макроса в «реальные» типизированные параметры.Последний операнд - это «возвращаемое значение», которое также имеет требуемый тип.

Обратите внимание, что компилятор выполняет правильную и прозрачную диагностику типов.
(Однако необходимо иметь некоторыепозаботьтесь об этих конструкциях, как объяснено в ссылке).

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

Более того, вы можете легко преобразовать его в реальную функцию, поскольку список параметров уже определен.Проверка типов уже выполнена, поэтому все будет работать нормально.В приведенном выше примере вы должны заменить все строки (кроме первой) следующими:

#define xxPseudoPrototype(RETTYPE, MACRODATA, ARGS) typedef struct { RETTYPE xxmacro__ret__; ARGS } MACRODATA

float SUM_intfloat(int x, float y) {                       /* (1) */
   xxPseudoPrototype(float, xxSUM_data, int x; float y; ); /* (2) */
   xxSUM_data xxsum;                                       /* (2) */
   return                                                  /* (3) */
     ( xxsum = (xxSUM_data){ .x = x, .y = y },             /* (4) (5) (6) */
         xxsum.xxmacro__ret__ = xxsum.x + xxsum.y,         /* (5) (6) */
         xxsum.xxmacro__ret__)                             /* (6) */ 
    ;                                                      /* (7) */
 }                                                         /* (8) */

Замена будет выполняться систематической процедурой:

(1) Макросзаголовок превратился в заголовок функции.Точки с запятой (;) заменяются запятыми (,).
(2) Строки объявления перемещаются внутри тела функции.
(3) Добавлено слово "return".
(4) Макроаргументы X,Y, заменяются параметрами функции x, y.
(5) Все конечные "\" удаляются.
(6) Все вычисления промежуточного выражения и вызовы функций остаются без изменений.
(7) Добавлена ​​точка с запятой.
(8) Корпус функции закрытия.

Проблема: Хотя этот подход решает ваши потребности, обратите внимание, что функция продублировала свой список параметров.Это не хорошо: псевдопрототипы и дубликаты должны быть удалены:

float SUM_intfloat(int x, float y) { 
   return  
     ( x + y )
    ;  
 }      
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...