LINUX.ORG.RU

Автогенерация бойлерплейта на Си

 , ,


0

2

Привет, ЛОР, надоело писать бойлерплейт-код руками, хочу сделать хеддерник с содержанием типа

/*foo.h*/
FOO(a)
FOO(b)
FOO(c)
FOO(d)

А потом где то в коде, или в другом хеддере

#define FOO(...) BAR1(__VA_ARGS__)
#include <foo.h>
#undef 

#define FOO(...) BAR2(__VA_ARGS__)
#include <foo.h>
#undef

В том числе хочется делать таким образом enum.

Вопросы: 1. Есть ли возможность в таком enum генерировать конкретные численные значения так, чтобы такой enum потом можно было инклюдить в разные файли и значения везде были одни?

2. Есть ли способ генерировать последовательность констант без enum, и так, чтобы не жралась память?

хеддерник с содержанием типа

Именно 5 вызовов FOO? Я надеюсь, у тебя ничего не получится.

При определенной ловкости рук можно сделать макрос, который позволит писать FOO(EnumIdent, Const1, 23, Const2, 25, ...), но это не имеет смысла для определения enum.

tailgunner ★★★★★
()

Видел я не так давно код одного такого любителя кодогенерации на сишном препроцессоре. Не делай так, пожалей коллег.

Gvidon ★★★★
()

А взять плюсовые шаблоны, а код оставить по-максимуму сишным не?

Dark_SavanT ★★★★★
()

Уже сказали, что это называется X Macro. Встречается в жизни, обычно в нетривиальных проектах и сравнимой альтернативы нет.

1. Есть ли возможность в таком enum генерировать конкретные численные значения так, чтобы такой enum потом можно было инклюдить в разные файли и значения везде были одни?

FOO(a, 666)

?

2. Есть ли способ генерировать последовательность констант без enum, и так, чтобы не жралась память?

Если и можно, то это не просто. Нужен будет список всех элементов, и потом каждый элемент определить как предыдущие +1. Не знаю, насколько это реально. Если значения не важны, то можно __LINE__. Но этот пункт как-то странно выглядит, не понятно зачем так делать.

xaizek ★★★★★
()

Не понял вопросов, если честно.

Если тебе нужеy enum с последовательными значениями, что просто бери макрос, принимающий значение первого элемента в enum.

Если же тебе нужно генерировать что-то сложнее, чем

 enum { a = 666, b, c}
, то очевидно, что говнопроцессор тьюринг неполный, а значит никаких вычислений в компайлтайме.

Вывод: бери m4, ocaml, perl или python и лепи генерацию, если текстовой подстановки не хватает. Ну или бери кресты, правда, крестовые шаблоны — говно на уровне m4, а их константные выражения на деле имеют такой ворох ограничений, что не сильно лучше шаблонов, так что хрен редьки не слаще.

А вообще тру си вэй — задать все константы руками, ну либо используй сторонний кодогенератор, если лентяй такой.

чтобы не жралась память?

Так тебе в рантайме или в компайл тайме генерировать?

anonymous
()

быдлокодненько так...

#define ABCD(f,a,b,c,d) f(a),f(b),f(c),f(d)

ABCD(foo,1,2,3,4);
ABCD(bar,1,2,3,4);

игры с константами и сериями вызовов можно ещё обеспечивать через gas - у него на это средств больше.

MKuznetsov ★★★★★
()

Напиши скрипт на руби и генерируй им все что тебе нравится в процессе конфигурации и сборки

invy ★★★★★
()

Вопросы: 1. Есть ли возможность в таком enum генерировать конкретные численные значения так, чтобы такой enum потом можно было инклюдить в разные файли и значения везде были одни?

а сейчас у тебя enums не так работают? в них если не указывать значения, будет 0,1,2,3,4.... — всегда одинаково. или подразумевается что-то другое?

Есть ли способ генерировать последовательность констант без enum, и так, чтобы не жралась память?

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

waker ★★★★★
()
Ответ на: комментарий от vvviperrr

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

hateyoufeel ★★★★★
()
Ответ на: комментарий от tailgunner

Спасибо, я вас тоже очень люблю!

(ц)Масяня

shkolnick-kun ★★★★★
() автор топика
Ответ на: комментарий от someoneelsenotme

Ух ты! У этого паттерна есть название!

Я его применял уже, просто enum делать не приходилось...

shkolnick-kun ★★★★★
() автор топика
Ответ на: комментарий от MKuznetsov

игры с константами и сериями вызовов можно ещё обеспечивать через gas - у него на это средств больше.

Это для BuguRTOS и другого низкоуровневого системного кода типа cstartup, там не везде есть gas.

shkolnick-kun ★★★★★
() автор топика
Ответ на: комментарий от waker

а сейчас у тебя enums не так работают? в них если не указывать значения, будет 0,1,2,3,4.... — всегда одинаково. или подразумевается что-то другое?

Это понятно, просто хотелось указать значения более явно, чтобы значение попадали в uint8_t, насколько я понимаю, в Си enum - это фактически int, если не применять специальные фичи компилятора...

shkolnick-kun ★★★★★
() автор топика
Ответ на: комментарий от shkolnick-kun

Это понятно, просто хотелось указать значения более явно, чтобы значение попадали в uint8_t, насколько я понимаю, в Си enum - это фактически int, если не применять специальные фичи компилятора...

уточни, какие именно фичи компилятора - тогда можно подумать.

waker ★★★★★
()
Ответ на: комментарий от waker

У некоторых компиляторов бывает опция оптимизации, отвечающая за размер enum, это непереносимо от слова совсем, так что в топку.

shkolnick-kun ★★★★★
() автор топика
Ответ на: комментарий от shkolnick-kun

Так а чем не нравится такое?

#define FOO(...) __VA_ARGS__,
enum {
    // offset = 123,
#include <foo.h>
};
#undef FOO
Если нужно тип поменять, то сделать значения перечисления с префиксом, а потом нагенерировать локальных констант нужного типа и инициализированных элементами перечисления. Неиспользованные константы должны быть удалены компилятором.

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

Думаю, что самый здравый вариант, — задать значения явно руками, а дальше будут приведения типов, ибо байтики на стеке хочется сэкономить.

Всем спасибо!

shkolnick-kun ★★★★★
() автор топика
Последнее исправление: shkolnick-kun (всего исправлений: 1)
Ответ на: комментарий от shkolnick-kun

Это понятно, просто хотелось указать значения более явно, чтобы значение попадали в uint8_t, насколько я понимаю, в Си enum - это фактически int, если не применять специальные фичи компилятора...

Никто при этом не мешает делать так.

enum {
    A,
    B,
    C
};

uint8_t a = A;

deadskif
()

Твои многократные инклюды напомнили мне мои велосипеды: тыц и тыц.

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

Насчет кодогенерации — можно ведь в Makefile или CMakeLists.txt засунуть дополнительную цель и генерировать хоть баш-скриптом, хоть сишной фиговиной (скажем, я себе при работе с CUDA размеры блоков и флаги nvcc генерировал при сборке — дополнительной утилиткой).

anonymous
()
Ответ на: комментарий от anonymous

Твои многократные инклюды напомнили мне мои велосипеды: тыц и тыц.

Не, у тебя аналог шаблонов, такое используется в том числе в cblas.

только конструкции типа

        uint8_t p = *iptr << 1 | *iptr >> 1
	#ifndef IM_UP
		| iptr[-W]
	#endif
	#ifndef IM_DOWN
		| iptr[W]
	#endif

Надо заменить на


#ifndef IM_UP
#define P_IM_UP |iptr[-W]
#else
#define P_IM_UP
#endif

#ifndef IM_DOWN
#define P_IM_DOWN |iptr[W]
#else
#define P_IM_DOWN
#endif

#define P_DECL uint8_t p = *iptr << 1 | *iptr >> 1 P_IM_UP P_IM_DOWN;

А там именно что генерация всякого рода массивов для инициализации всяких там портов или всяких там таблиц векторов прерываний.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.