LINUX.ORG.RU

Препроцессор c/c++. Подстановка/макрогенерация.

 , ,


0

2

Hi all!

Подскажите плиз как (и реально ли) сделать что то подобное?

#define VARIANT small
// #define VARIANT large                                                                                                                                                                                             

#include "config_##VARIANT##.h"

void main_small() { /* ... */ }
void main_large() { /* ... */ }

int main(void) {
  main_#VARIANT##();
}

пока получается только как то так:

/* g++ -DVARIANT_LARGE test.cpp */

#ifdef VARIANT_LARGE
#include "test_large.h"
#endif

#ifdef VARIANT_SMALL
#include "test_small.h"
#endif

void main_small() { /* ... */ }
void main_large() { /* ... */ }

int main(void) {

  #ifdef VARIANT_LARGE
  main_large();
  #endif

  #ifdef VARIANT_SMALL
  main_small();
  #endif

  return 0;
}

★★

Ответ на: комментарий от Stil

да вот очень хочется как то так:

#define STRINGIZE_(a) #a
#define STRINGIZE(a) STRINGIZE_(a)

#define EXT small
#include STRINGIZE(test_EXT.h)
а так не катит:

$ g++ -DVARIANT_LARGE test.cpp && ./a.out 
test.cpp:6:31: fatal error: test_EXT.h: No such file or directory
 #include STRINGIZE(test_EXT.h)
samson ★★ ()
#define VARIANT small

#define _expand_str(a) #a
#define _config(a) _expand_str(config_##a.h)
#define config(a) _config(a)

#include config(VARIANT)
staseg ★★★★★ ()
Ответ на: комментарий от samson

Смотри мой пример выше. По сути у тебя не хватает одного промежуточного действия, которое раскрывает EXT в значение.

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

сеньк. сразу не догадался...

а как быть с main_##VARIANT##(); ?

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

Я не уверен, что '#' или '##' подстановки работают вне определения макроса, точнее я почти уверен, что они не работают. Поэтому делай то же самое:

#define _MAIN(a) main_##a
#define MAIN(a) _MAIN(a)

...

MAIN(VARIANT)();
staseg ★★★★★ ()
Ответ на: комментарий от staseg

Но это все дурно пахнет. Лучше решить проблему на уровне линковки или в крайнем случае плагинами. Что суть тоже линковка :)

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

Спасибо. Вот так работает.

/* $ g++ -DVARIANT=small test.cpp */
#define _expand_str(a) #a
#define _config(a) _expand_str(test_##a.h)
#define config(a) _config(a)

#define _call_main(a) main_##a
#define call_main(a)  _call_main(a) 

#include config(VARIANT)

#include <iostream>
using namespace std;

void main_small() { cout << "small"; }
void main_large() { cout << "large"; }

int main() {
  call_main(VARIANT)(); /* сначала пытался последние скобки в макрос запихнуть - не вышло */
  cout << endl;
  return 0;
}

Я не уверен, что '#' или '##' подстановки работают вне определения макроса

не работают. Какраз в это сначала и уперся.

Лучше решить проблему на уровне линковки или в крайнем случае плагинами

Это надо для AVR. Поэтому плагины отпадают. А на уровне линковки как сделать в Eclipse (пока собирается все в IDE) не знаю.

samson ★★ ()
Последнее исправление: samson (всего исправлений: 2)
Ответ на: комментарий от samson

Не знаю, как оно в эклипсе настраивается, но суть в том, что создаешь три файла main.cpp, main_small.cpp и main_large.cpp. В small и large реализуешь функцию main_impl(), которую вызываешь из основного main. Потом создаешь два проекта (две конфигурации?) из одного выключаешь small-версию, из второго — large.

Упрощенно на уровне вызова компилятора это будет выглядеть так:

$ g++ main.cpp main-small.cpp -o small.exe
$ g++ main.cpp main-large.cpp -o large.exe

В итоге, если сам main ничего полезного не делает, это упрощение закончится выкидыванием main и написанием двух main-функций в small и large файлах :)

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

да это понятно. Просто не знаю, как в эклипсе так слинковать. Да оно и проще, как мне кажется. Создаешь кучу файлов config_bordX.h и main_boardX.cpp а в основном конфиге уже определяешь VARIANT, ну или при компиляции указываешь -DVARIANT=board2.

Кстати, на счет плагинов:

крайнем случае плагинами. Что суть тоже линковка :)

Разве в случае динамически подгружаемых плагинов это так?)

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

Хм. Когда я это писал, мне казалось, что это разновидность динамической линковки. Но наверное нет, я лоханулся в терминологии.

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

Терминологически - да, но по сути не сильно. «Плагины» в формате нативного кода - всё то же динамическое связывание кода времени исполнения, только управляемое пользователем программы, а не программистом на этапе сборки исполняемого образа.

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

А на уровне линковки как сделать в Eclipse (пока собирается все в IDE) не знаю.

Возьми и узнай, наконец, вместо того, чтобы страдать хернёй.

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

кстати, в догонку, можно ли препроцессором сделать что то подобное:

#if VARIANT == variant1
это уже чисто «спортивный» интерес.

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

Возьми и узнай, наконец, вместо того, чтобы страдать хернёй

Каждый раз лезть в настройки проекта и менять там что то? Как мне кажется не особо удобно. Тем более, что привязка к ide вообще не нужна.

Тут основной вопрос был как заинклудить нужный конфиг. Хотя и это можно реализовать по другому. Можно в разных директориях хранить config.h и main.cpp и скармиливать компилятору через -I эти директории. И, соответственно, собирать нужный main.

Так то вариантов куча. Вопрос именно про препроцессор.

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

В препроцессоре можно сравнивать только интегральные типы. Если ты сможешь с помощью какой-нибудь макро-магии свести VARIANT и variant1 к константным интам, то сможешь сравнить. Мне навскидку в голову ничего не пришло.

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

получается что стандартного варианта нет.

В принципе абсолютно согласен со всеми, что делать это средствами препроцессора не всегда есть гуд, сам не сторонник такого пути. Но в некоторых случаях, почему бы и нет...

Еще раз всем спасибо!

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