Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.60/48: Рейтинг темы: голосов - 48, средняя оценка - 4.60
0 / 0 / 0
Регистрация: 11.02.2013
Сообщений: 10
1

Использование строк в макросах С++

11.02.2013, 13:19. Показов 8812. Ответов 23
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Доброго времени суток всем!
Возникла небольшая проблема - не могу понять, возможно ли сделать нечто подобное, и, если возможно, то как.
Есть макрос, объявляющий функцию:

C++
1
2
3
4
#define DECLARE_FUNC(name1, body, type_cl, ...)\
    __declspec(dllexport) void type_cl name1##_func(__VA_ARGS__){\
    body;\
}\
Используется следующим образом:
C++
1
DECLARE_FUNC(testDeclare, "debug_msg(\"TestDeclare\",\"hello!\")", void, void);
где строка - вызов функции debug_msg(запись в файл форматированной строки).

Собственно, вопрос - как это сделать правильно? В текущем варианте нет никакой реакции на вызов функции testDeclare_func().

P.S. В следующем варианте
C++
1
2
3
4
5
#define DECLARE_FUNC(name1, body, type_cl, ...)\
    __declspec(dllexport) void type_cl name1##_func(__VA_ARGS__){\
    debug_msg("TestDeclare","hello!");\
    body;\
}\
вывод из debug_msg("TestDeclare","hello!"); вполне адекватно отрабатывает.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
11.02.2013, 13:19
Ответы с готовыми решениями:

Использование строк.Использование структур
Задачка: Дана строка,состоящая из групп нулей и едениц. Найти и вывести на экран группы с нечетным...

Метки в макросах в ассемблерной вставке
В C++ написан макрос с ассемблерной вставкой, который содержит в себе метку "doit" и команду...

Использование строк
Помогите с алгоритмом программы: вводим текст происходит проверка на наличие цифр прописью,...

Использование файлов и строк
Уважаемые программисты! Нужна ваша помощь, заканчиваю написание диплома и возникла следующая...

23
Модератор
3386 / 2158 / 352
Регистрация: 13.01.2012
Сообщений: 8,378
11.02.2013, 14:09 2
вы пытаетесь макросом объявить функцию и в то же время пытаетесь передать ей список аргументов. аргументы передаются во время вызова. наверное нужен макрос для вызова
0
0 / 0 / 0
Регистрация: 11.02.2013
Сообщений: 10
11.02.2013, 15:28  [ТС] 3
Какого рода макрос?
Если объявить функцию следующим макросом
C++
1
DECLARE_FUNC(testDeclare, "debug_msg(\"TestDeclare\",\"%d\", a1)", void, int a1);
и вызвать
C++
1
testDeclare(123);
то в файле получим вывод 123.

Или я неправильно понял смысл поста?
0
Модератор
3386 / 2158 / 352
Регистрация: 13.01.2012
Сообщений: 8,378
11.02.2013, 15:39 4
вот во что будет преобразован макрос
C++
1
2
3
__declspec(dllexport) void void testDeclare_func(ЗДЕСЬ БУДЕТ АД - Я ДАЖЕ НЕ ЗНАЮ КАК ПРЕПРОЦЕССОР ОБРАБОТАЕТ INT A1){
    "debug_msg(TestDeclare,%d, a1)";
}
Добавлено через 1 минуту
__VA_ARGS__ можно было бы скормить вызову функции но не определению то есть
C++
1
CALL_MY_STRANGE_FUNC(name, __VA_ARGS__) name(__VA_ARGS__);
0
0 / 0 / 0
Регистрация: 11.02.2013
Сообщений: 10
11.02.2013, 21:45  [ТС] 5
Пардон, торопился, ошибся, когда в уме модифицировал.
Переделывал из рабочего макроса

C++
1
2
3
4
5
#define RF_O(ret, type_cl, name1, adres, ...)\
    typedef ret ( type_cl * t##name1 ) ( __VA_ARGS__ );\
    /*__declspec(dllexport) */t##name1 __declspec(dllexport) name1##_Detour = ( t##name1 ) ( adres );\
    __declspec(dllexport) void type_cl name1##_hook(__VA_ARGS__);\
    BYTE name1##_var[6];\

Реальный код таков:
C++
1
2
3
4
5
6
7
8
9
10
11
12
#define DECLARE_FUNC(name1, body, type_cl, ...)\
    __declspec(dllexport) void type_cl name1##_func(__VA_ARGS__){\
    debug_msg("TestDeclare","hello!");\
    body;\
}\
 
 
#define RF_IMP(ret, type_cl, body, name1, ...)\
    DECLARE_FUNC(name1,body,type_cl, __VA_ARGS__);
 
char *declare = "debug_msg(\"TestDeclare\",\"hello!\")";
RF_IMP(void, __cdecl, declare,testDeclare,void);
В таком варианте полученная функция выглядит так:

C++
1
2
3
4
5
6
__declspec(dllexport) void __cdecl name1_func(void);
 
void __cdecl name1_func(void)
{
body;
}

Вот проблема в том, как обработать body.

P.S. Код рабочий, за исключением того, что не в курсе, как строку преобразовать в тело функции. Если подставить туда a1(ну или любые другие аргументы) + написать тело вручную, то все будет работать отлично. К примеру, аналогичный макрос предназначен для универсального парса lua_State перехваченных функций в 1 игрушке, использующей луа-движок.
0
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
11.02.2013, 22:14 6
demogor, вы забываетесь. C/C++ - это компилируемые языки. Т.е. перед запуском куска кода - он должен быть скомпилирован! Т.е. невозможно выполнить в программе код, который помещен в текстовую строку. Это возможно в большинстве скриптовых языков, таких как Python, но никак не C++.
А при компиляции, компилятор возьмет строку RF_IMP(void, __cdecl, declare,testDeclare,void); затем преобразует ее в DECLARE_FUNC(testDeclare,declare,__cdecl, void); затем это преобразует в
__declspec(dllexport) void type_cl testDeclare_func( void ){
debug_msg("TestDeclare","hello!");
declare;
}
А затем полученный код он будет дальше компилировать. Т.е. как видно, вместо body подставиться просто строка теста, то никак не тело функции, которое вы хотите сделать.

Добавлено через 4 минуты
Стоит запомнить, что макросы никаким образом не работают с содержимым перменных, только с именами.
Например
C++
1
2
3
4
#define print(a, b) cout << a##b
void main( void ) {
  int x = 1, y = 2;
  split(x, y);
Результат будет не 12, как вы ожидаете, а ошибка компиляции, так как как видно в дефайне, он вместо a подставит x, вместо b - y, склеит их и получит xy. Т.е. в итоге попытается вывести переменную с именем xy, которая не определена.
1
0 / 0 / 0
Регистрация: 11.02.2013
Сообщений: 10
11.02.2013, 22:17  [ТС] 7
Понял, собственно это меня и интересовало, благодарю за ответ)
А есть ли возможность импорта тела функции из lua? Можно импортировать всю функцию, конечно, но это не самый идеальный вариант.
0
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
11.02.2013, 22:24 8
demogor, ни разу не работал с Lua. Но как я понял - это скриптовый язык? Обычно, такое реализуется сторонней библиотекой. Что-то есть тут, что-то тут. Вообще много чего можно найти в гугле по запросу "Lua in C++".
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
11.02.2013, 22:29 9
Цитата Сообщение от demogor Посмотреть сообщение
Понял, собственно это меня и интересовало, благодарю за ответ)
А есть ли возможность импорта тела функции из lua? Можно импортировать всю функцию, конечно, но это не самый идеальный вариант.
Я не очень понимаю смысла фразы "импорта тела функции из lua". Если ты хочешь исполнить код Lua из-под Си/Си++, то можешь тут посмотреть: https://www.cyberforum.ru/cpp-... 68085.html. В посте #8 конкретный пример (который никак не зависит от конкретного компилятора)
0
0 / 0 / 0
Регистрация: 11.02.2013
Сообщений: 10
11.02.2013, 22:54  [ТС] 10
Да не, как импортировать функции туда-обратно, я представляю. Хотел реализовать просто обертку для перехвата функций(много достаточно однотипных функций, объявлять их уже наловчился, было бы неплохо добавить возможность изменять код извне, что бы каждый раз не ребилдить dll'ку).
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
12.02.2013, 00:01 11
Что такое "обёртка для перехвата функций"?
0
0 / 0 / 0
Регистрация: 11.02.2013
Сообщений: 10
12.02.2013, 00:24  [ТС] 12
Неточно выразился.
Я имел в виду макросы для объявления функций, используемых для перехвата оригинальных функций.

C++
1
2
3
RF_O(void, __cdecl, lua_state, 0xCB62B0, lua_State *L, const char *libname, const luaL_Reg *l);
RF_O(void, __cdecl, luaLoadLibs, 0x8E9760, lua_State *L);
RF_O(void, __cdecl, lua_setfield, 0xCE63B0, lua_State *L, int index, const char *k);
К примеру.

Функции объявил, рассчитал адрес в памяти(если он не статический), поставил хук - и нужно бы описать функции, но пока это приходится делать вручную.
Правда, можно обойтись и простым логированием, для начала вполне сойдет.
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
12.02.2013, 09:02 13
Из этого тебе надо родить макрос RF_O? А что за константа в 4-м параметре? Есть такая умная мысль: "грамотно поставленный вопрос - это уже половина ответа". Я примерно понимаю, что тебе надо, но не пойму, что же конкретно

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

Код

C++
1
2
3
4
5
6
#define DECLARE_FUNC(name1, body, type_cl, ...) \
  __declspec(dllexport) type_cl name1##_func(__VA_ARGS__) {\
    body; \
  }
 
DECLARE_FUNC (testDeclare, debug_msg ("TestDeclare", "hello!"), void, int x, int y)
после препроцессора превратится в

C++
1
__declspec(dllexport) void testDeclare_func(int x, int y) { debug_msg ("TestDeclare", "hello!"); }
Правда я не пойму, чем такие извращения с макросами дают преимущество по сравнению с ручным описанием функции. Лично я ни одного преимущества не вижу

Добавлено через 1 минуту
Может вот это тебе чем-то поможет: https://www.cyberforum.ru/blogs/18334/blog100.html
0
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
12.02.2013, 10:07 14
Evg, как я понял, у него есть библиотееа на C++. Но ее нужно очень часто менять, но ему очень не хочется постоянно ее перекомпилировать для этого. Поэтому он хочет, чтобы внутри его библиотеки использовались функции из скриптового языка. Т. е. можно поменять что-то в библиотеке просто изменив функции в скрипте.
0
Kastaneda
12.02.2013, 10:18
  #15

Не по теме:

Видел пример использования подобных вещей в одном из рабочих проектов.
Например вот подобная жесть

Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#define DEFINE_ENUM_MAP(type,descr) \
template<>\
const char* toString<type>(type e) {\
    cnvResult = true;\
    for(uint16 i = 0; i < g##type##Len; i++) {\
        if (g##type##Names[i].e == e) {\
            return g##type##Names[i].s;\
        }\
    }\
    cnvResult = false;\
    /* warning("Value %d for type %s has no string representation", e, #type); */ \
    return NULL;\
}\
\
template<>\
type fromString<type>(const char* s, type def) {\
    cnvResult = true;\
    for(uint16 i = 0; i < g##type##Len; i++) {\
        if (!strcmp(g##type##Names[i].s,s)) {\
            return g##type##Names[i].e;\
        }\
    }\
    warning("Can not convert string \"%s\" to value of type %s", s, #type);\
    cnvResult = false;\
    return (type)def;\
}\
\
template<> string getAllStrings<type>(const type* e, uint16 size){\
    string res;uint16 i;\
    if ( !e || !size ) {\
        if (size) {\
            res = #type;\
        } else {\
            for(i = 0; i < g##type##Len; i++) {\
                if ( i > 0 ) res += ',';\
                res += g##type##Names[i].s;\
            }\
        }\
    } else  {\
        res = arrToString<type>(e,size);\
    }\
    return res;\
}\
\
template<>\
const char* getTypeDescription<type>(type e) {return g##type##Descrip;}\
\
template<>\
string getAllItemsDescription<type>(type e) {\
    string res;uint16 i,c=0;\
    for(i = 0; i < g##type##Len; i++) {\
        if ( c > 0 ) res += '\n';\
        if ( g##type##Names[i].d ) {\
            res += g##type##Names[i].s;\
            res += '\t';\
            res += g##type##Names[i].d;\
            c++;\
        }\
    }\
    return res;\
}\
\
template<>\
const char* getItemDescription<type>(type e) {\
    for(uint16 i = 0; i < g##type##Len; i++) {\
        if (g##type##Names[i].e == e) {\
            return g##type##Names[i].d;\
        }\
    }\
    return 0;\
}\
\
const char* g##type##Descrip=descr;\
const CTG##type##Map g##type##Names[g##type##Len] = {
 
// Closing macro for enum to string mapping
#define END_ENUM_MAP }

1
Модератор
3386 / 2158 / 352
Регистрация: 13.01.2012
Сообщений: 8,378
12.02.2013, 10:46 16
Цитата Сообщение от Evg Посмотреть сообщение
после препроцессора превратится в
я думал что препроцессор споткнется об запятую перед hello, но пример работает. как это возможно?
1
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
12.02.2013, 22:05 17
Цитата Сообщение от nonedark2008 Посмотреть сообщение
Evg, как я понял, у него есть библиотееа на C++. Но ее нужно очень часто менять, но ему очень не хочется постоянно ее перекомпилировать для этого. Поэтому он хочет, чтобы внутри его библиотеки использовались функции из скриптового языка. Т. е. можно поменять что-то в библиотеке просто изменив функции в скрипте.
Ну... при такой постановке вопроса в компилируемых языках настолько просто это не решается.

Цитата Сообщение от vxg Посмотреть сообщение
я думал что препроцессор споткнется об запятую перед hello, но пример работает. как это возможно?
Слушай, хороший вопрос. Мне казалось чем-то самим собой разумеющимся то, что наличие скобок экранирует запятые. Причём наверняка оно так и есть, но я как-то никогда об этом не задумывался, просто использовал и всё. Надо бы почитать
0
0 / 0 / 0
Регистрация: 11.02.2013
Сообщений: 10
12.02.2013, 22:29  [ТС] 18
Evg, если о lua_State(
А что за константа в 4-м параметре?
), то это состояние текущего экземпляра луа интерпретатора. Честно говоря, сам не до конца понимаю смысла его, потому представляю как некий контейнер, содержащий аргументы lua функции(стек, по факту).
Вариант подачи тела, предоставленный выше, логичен, но хотелось именно строку передавать, что бы была возможность вытягивать тело функции из отдельного файла(nonedark абсолютно прав).
Необходимость этого в том, что я разбираю потихоньку клиент и для получения информации о функциях их необходимо перехватывать. Каждый раз, что бы это сделать, необходимо описывать функции - а это не слишком удобно. Именно для этого и нужны макросы, потому и хочу максимально автоматизировать процесс.
Более того, в принципе, для начала меня вполне устроит макрос, который будет объявлять и описывать функцию с выводом аргументов в файл при перехвате.
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
12.02.2013, 22:39 19
Цитата Сообщение от demogor Посмотреть сообщение
Вариант подачи тела, предоставленный выше, логичен, но хотелось именно строку передавать, что бы была возможность вытягивать тело функции из отдельного файла(nonedark абсолютно прав)
Для компилируемого языка сие попросту нормально не реализуемо. Единственный способ - это из программы сгенерить файл на Си, далее из программы же вызвать компилятор и сформировать динамическую библиотеку, далее из программы же эту библиотеку подключить (в unix-системах есть интерфейс dlopen и ко, наверняка в винде есть то же самое). Либо использовать всякие нанотехнологии типа OpenCL, которые по большому счёту точно так же являются вызовом компилятора, только всё это монолитно встраивается в программу.

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

Добавлено через 1 минуту
А в целом я твою задачу всё равно не понимаю из-за невнятной постановки

Ну или могу порекомендовать на ходу генерировать функции на Lua, а не на Си. Интерпретатор Lua встраивается в программу, а потому сие вполне допустимо
0
0 / 0 / 0
Регистрация: 11.02.2013
Сообщений: 10
12.02.2013, 22:49  [ТС] 20
Я хочу добавлять хуки сразу из луа, но для этого нужно как-то описывать тело функции(а не только ее декларировать). Вариант с подачей из текстового файла сначала показался самым подходящим но, как я уже понял, это не представляется возможным.
Впрочем, думаю, мне вполне хватит варианта с выводом аргументов.
0
12.02.2013, 22:49
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
12.02.2013, 22:49
Помогаю со студенческими работами здесь

Использование строк и файлов
С помощью текстового редактора создать файл, содержащий текст, длина которого не превышает 1000...

Использование одномерного массива строк
Здравствуйте! Задание: Имеется файл 1.txt в котором содержатся строки неизвестной длины. Так же...

Использование строк(как правильно?)
Здравствуйте! Была где-то реализация (условно) const char buffer; int i=0;...

Использование собственного класса строк
Здравствуйте, уважаемые господа. Есть реализация собственного класса строк: class MyString {...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru