С Новым годом! Форум программистов, компьютерный форум, киберфорум
Наши страницы

C++

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 19, средняя оценка - 4.74
Izual
94 / 119 / 6
Регистрация: 13.11.2012
Сообщений: 1,556
#1

Альтернативный вызов функции - C++

15.08.2014, 10:44. Просмотров 2846. Ответов 66
Метки нет (Все метки)

1. Интересует метод вызова функции через указатель(или по другому).
2. Интересует метод взятия кол-ва аргументов функции и их типов, а так же тип возвращяемого значения.

По второму пункту вообще ничего не нашёл, а по первому есть некоторые вопросы.
C++
1
2
3
4
5
6
7
8
9
#include "FTD2XX.h" // библиотека от FTDI
typedef FT_STATUS (*pFT_Open) (int, FT_HANDLE *); // тип данных "функция FT_OPEN"
 
HMODULE hMod = LoadLibrary ("FTD2XX.dll"); // загрузка библиотеки - д. б. не ноль
pFT_Open pOpen = GetProcAddress (hMod, "FT_Open"); // получили адрес функции - также д. б. не ноль
 
FT_STATUS st = pOpen (0, &hDev);    // вызываем функцию
 
FreeLibrary (hMod); // закрыли библиотеку
Нашёл вот такой вот вызов функции через строку названия функции "FT_Open". Меня интересует, если не создавать DLL, то можно ли как то вызвать подобным способом стандартную функцию (например из winuser.h)?

Ещё заинтересовало такое:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <string.h>
void check(char *a, char *b, int (*cmp) (const char *, const char *));
int main(void)
{
char s1 [80], s2[80];
int (*p) (const char*, const char*);
p = strcmp; /* получение адреса strcmp() */
gets(s1);
gets (s2);
check(s1, s2, p);
return 0;
}
 
void check (char *a, char *b, int (*cmp) (const char *, const char *))
{
printf("Testing for equality.\n");
if(!(*cmp) (a, b)) printf("Equal");
else printf("Not equal");
}
Однако тут явно указывается кол-во членов и их тип :
C++
1
int (*p) (const char*, const char*);
Что мне не подходит, можно как то это преодолеть? И ещё меня не устраивает что надо явно писать:
C++
1
p = strcmp;
А не строковой (char *) переменной, что дало бы возможность динамики (ну именно это в конечном итоге меня и интересует).

П.С. Если это возможно, приводите пожалуйста примеры без использования STL и классов, а более приближенными к Си методами.

Вообще по поводу пункта 2: подумалось, что если реализовать пример1, то нужен будет список функций, который я в принципе могу хранить в txt фале вместе с кол-вом аргументов и возвращяемым значением, хотя это будет тупое копирование строк из .h файлов, к примеру из winuser будут подобия:
C++
1
WINUSERAPI LRESULT WINAPI SendMessageA(HWND,UINT,WPARAM,LPARAM);
От сюда я могу "запарсить" и искомое извлечь для выполнения операции. Не думаю что будет смысл париться над пунктом2, т.к. игра не стоит свеч, значит стаётся открытым вопрос первый.

Добавлено через 29 минут
Узнал что это:
C++
1
typedef FT_STATUS (*pFT_Open) (int, FT_HANDLE *);
являет прототипом функции. В общем вот эту инициализацию прототипа можно обойти? Т.е. подразумеваю что например у меня будет динамический массив с переменными, после парсинга я получу типы, и согласно им - заполню массив. Далее если бы можно было бы реализовать вызов GetProcAddress с сылкой на массив, то хотелось бы чтоб автоматически передавались в аргументы значения массива от [1] и до кол-ва аргументов ( [0] аргумент думаю будет идти как возвращяемое значение функции)... (может как то можно использовать в данном случае переменное кол-во аргументов в функции?)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
15.08.2014, 10:44
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Альтернативный вызов функции (C++):

Вызов функции из dll - C++
Доброго времени суток! Пытаюсь вызвать функцию, которая находится в библиотеке следующим способом: HINSTANCE dllhandle =...

Функции в Assembler, вызов функции в C++ - C++ Builder
Здравствуйте, я составил функции на языке Assembler и вставил ее в код на C++: extern &quot;C&quot; { int INCREMENT(int a); } _asm {...

Вызов функции - C++ Builder
Собственно интересует как можно один раз вписать функцию с выполнением определенного алгоритма, так, чтоб потом когда понадобится этот...

Вызов функции - C++ Builder
В коде создания формы используется процедура: ... DrawSurface(A, B, C, T, drawpoint, X0, Y0, 10); ... Объявление DrawSurface ...

Вызов функции в событии - C++ Builder
На форме есть различные компоненты (баттоны, трекболлы, комбобоксы, пейджконтрол). Подскажите пожалуйста какое общее событие использовать...

BASS_ChannelSetSync вызов функции - C++ Builder
Может название не совсем верно. Есть переменная HSYNC PlaySync есть две функции void FreeStream (HSTREAM Stream) { ...

66
Izual
94 / 119 / 6
Регистрация: 13.11.2012
Сообщений: 1,556
17.08.2014, 08:43  [ТС] #31
DrOffset, я нашёл другой выход, хотя он не так красив как тот который я хотел бы использовать (с троеточием), но зато решает проблему.

C++
1
typedef int(_stdcall *Make_func)(void *,void *,void *,void *);
Естественно, придётся от 0 до 10 прототипов сделать(соответствующих кол-ву аргументов), и возвращяемое значение так же привести к void* (что я попробую чуть позже).
0
DrOffset
7377 / 4454 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
17.08.2014, 15:36 #32
Цитата Сообщение от Izual Посмотреть сообщение
я нашёл другой выход
Не будет работать с целыми больше 32 разрядов на 32 битной архитектуре, не будет работать с числами с плавающей точкой.
В общем в каких-то случаях работать будет, но это точно не самое корректное решение. Имей это в виду.

Добавлено через 2 минуты
Почитал бы ты литературу, на самом деле. А то, что сейчас - это же чистое шаманство. Хоть бы узнал на что тебе можно рассчитывать, а на что нет.
0
StailGot
28 / 23 / 6
Регистрация: 25.08.2013
Сообщений: 41
17.08.2014, 16:47 #33
Цитата Сообщение от DrOffset Посмотреть сообщение
Провел небольшое исследование. VS игнорирует stdcall для прототипа такого вида
Так и должно быть.
The called function cleans the stack, unlike CDECL. This means that STDCALL doesn't allow variable-length argument lists.
Подробнее тут и еще тут.

Альтернативный вариант:
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
#include <windows.h>
#include <windowsx.h>
#include <iostream>
 
using namespace std;
 
//typedef int( _stdcall *Make_func )( HWND, char *, char *, UINT );
 
//typedef int( _stdcall *Make_func )( ... ); // _stdcall не может иметь переменное число аргументов.
                                             // [url]http://en.wikibooks.org/wiki/X86_Disassembly/Calling_Conventions#STDCALL[/url]
 
template<typename ...Args>
auto get_type( Args ... ) -> int( _stdcall *)( Args... ); // а вот так может.
 
int main()
{
  char fn[] = "MessageBoxA";
  int res = 0;
  HMODULE hMod = LoadLibraryA ( "user32.dll" );
  if ( !hMod )
    cout << "Library not loaded" << endl;
  else
  {
    void * me = GetProcAddress( hMod, fn );
    if ( !me )
      cout << "Function not loaded" << endl;
    else
    {
      using func_type = decltype( get_type((HWND)NULL, "hi", "message", (UINT)NULL) ); // выведем тип функции по ее аргументам
      res = ( (func_type)me ) ( (HWND)NULL, "hi", "message", (UINT)NULL );
 
      cout << res << endl;
    }
    FreeLibrary ( hMod );
  }
  return 0;
}
Добавлено через 12 минут
Упрощенный вариант
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
#include <windows.h>
#include <windowsx.h>
#include <iostream>
 
using namespace std;
 
//typedef int( _stdcall *Make_func )( ... ); // _stdcall не может иметь переменное число аргументов.
                                             // [url]http://en.wikibooks.org/wiki/X86_Disassembly/Calling_Conventions#STDCALL[/url]
 
// а вот так может.
template<typename ...Args>
int call( void * fun, Args ... args)
{
 using func_type = int( _stdcall *)( Args... ); // выведем тип функции по ее аргументам
 return ( (func_type)fun ) ( args... );
}
 
 
int main()
{
  char fn[] = "MessageBoxA";
  int res = 0;
  HMODULE hMod = LoadLibraryA ( "user32.dll" );
  if ( !hMod )
    cout << "Library not loaded" << endl;
  else
  {
    void * me = GetProcAddress( hMod, fn );
    if ( !me )
      cout << "Function not loaded" << endl;
    else
    {
      res = call(me, (HWND)NULL, "hi", "message", (UINT)NULL );
      cout << res << endl;
    }
    FreeLibrary ( hMod );
  }
  return 0;
}
3
DrOffset
7377 / 4454 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
17.08.2014, 16:53 #34
StailGot, качественный workaround.
Только вместо void *, для передачи указателя, лучше использовать FARPROC.
0
Izual
94 / 119 / 6
Регистрация: 13.11.2012
Сообщений: 1,556
17.08.2014, 19:59  [ТС] #35
Цитата Сообщение от DrOffset Посмотреть сообщение
Не будет работать с целыми больше 32 разрядов на 32 битной архитектуре, не будет работать с числами с плавающей точкой.
Я как нибудь обойдусь 32 разрядами, а по поводу плавающей точки - печаль(не уж то даже float не будет работать с его разрядностью в 4 байта?)
Цитата Сообщение от DrOffset Посмотреть сообщение
Почитал бы ты литературу, на самом деле.
На самом деле уже третий день капаю гугл, но не зная что и где копать - много не выкопаеш.

StailGot, то что вы показали это не вариант для меня, я сразу сказал что векторы и STL не предлогать.
0
DrOffset
7377 / 4454 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
17.08.2014, 20:20 #36
Цитата Сообщение от Izual Посмотреть сообщение
я сразу сказал что векторы и STL не предлогать.
Это не вектор и не STL ) Это текущий стандарт С++11, используются только базовые возможности, которые часть языка.
Цитата Сообщение от Izual Посмотреть сообщение
На самом деле уже третий день капаю гугл, но не зная что и где копать - много не выкопаеш.
Да я не про гугл, а про книжки, того же Рихтера или Руссиновича. И по ассемблеру что-нибудь.
В интернете вообще вся толковая информация на английском, ища на русском много не накопаешь. Вот ссылку хотя бы изучи, которуя я уже давал, про calling convetions.
Цитата Сообщение от Izual Посмотреть сообщение
не уж то даже float не будет работать с его разрядностью в 4 байта?
А это уже вопрос твоего понимания что такое целое число и что такое число с плавающей точкой и как они передаются на стек и снимаются со стека.
Assembler
1
movsd   QWORD PTR [esp], xmm0
Для справки, QWORD - это 8 байт, хотя в С++ коде, из которого я вынул эту инструкцию, передавал float.
0
Izual
94 / 119 / 6
Регистрация: 13.11.2012
Сообщений: 1,556
17.08.2014, 21:03  [ТС] #37
Цитата Сообщение от DrOffset Посмотреть сообщение
Это не вектор и не STL
template, разве?..
Цитата Сообщение от DrOffset Посмотреть сообщение
стандарт С++11
Блин, реально *bored*, мне эти нынешние стандарты по барабану, сколько раз сказать это чтоб уже поняли, что я смотрю не на стандарты, а на простоту понимания. Программирование и так то достаточно сложное, а то что сейчас выводится в стандарты только лишь опускает нас в бездну(сутками чтоли изучать всё появляющиеся стандарты?), а в конце результат - "у нас времени не было", как скажут многие на многие не сделанные вещи, время на которые сожрало изучение догматики.(а стандарты это и есть догматика)
Цитата Сообщение от DrOffset Посмотреть сообщение
вся толковая информация на английском
Ну так я переводчиком, тока один хрен слишком много непонятных моментов между строк, потому результат стремится к нулю)
Цитата Сообщение от DrOffset Посмотреть сообщение
А это уже вопрос твоего понимания
Нет, мы смотрим фактически на <= 32 бита(т.е. 4 байта).

П.С. Как же много всякой ерунды напридумывали, лишь бы людей отвлечь от действительно важных вещей... Вспомнился фильм "Generation П" : "Народу нужна хорошая драка, тогда он про всё забудет, про жену, про квартиру..."
0
DrOffset
7377 / 4454 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
17.08.2014, 22:41 #38
Цитата Сообщение от Izual Посмотреть сообщение
template, разве?
Разве. Это часть языка. STL - это библиотека, и она не часть языка.

Цитата Сообщение от Izual Посмотреть сообщение
Ну так я переводчиком, тока один хрен слишком много непонятных моментов между строк, потому результат стремится к нулю)
Английский учи Переводчик там тебе напереводит пожалуй.

Учись, все равно как-то семью кормить потом придется
0
Izual
94 / 119 / 6
Регистрация: 13.11.2012
Сообщений: 1,556
17.08.2014, 23:30  [ТС] #39
Цитата Сообщение от DrOffset Посмотреть сообщение
часть языка.
векторы часть, да. Только условие было делать без них..

Не по теме:

есть разные пути, не только "оседлые"
Омммм..

0
DrOffset
7377 / 4454 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
17.08.2014, 23:50 #40
Цитата Сообщение от Izual Посмотреть сообщение
векторы часть, да. Только условие было делать без них..
Опять ты невнимательно читаешь. Векторы - это не часть языка, это часть стандартной библиотеки, оно же STL, а ключевое слово template - часть.
Формально условие выполнено было
0
Izual
94 / 119 / 6
Регистрация: 13.11.2012
Сообщений: 1,556
19.08.2014, 08:17  [ТС] #41
Что то пример который дал StailGot не компилится... на VStudio(2005)

1. Ошибка:
template<typename ...Args>
error C2143: syntax error : missing ',' before '...'
2. Ошибка:
int call( void * fun, Args ... args)
error C2061: syntax error : identifier 'Args'
3. ещё одна в вызове самой функции:
res = call(me, (HWND)NULL, "hi", "message", (UINT)NULL );
error C2780: 'int call(void *)' : expects 1 arguments - 5 provided
Почему так?

Добавлено через 13 минут
Кстати нашёл на MSDN эту тему... http://msdn.microsoft.com/ru-ru/library/dn439779.aspx
но почему же компиляционные ошибки то(

Добавлено через 9 минут
При этом MSDN пишет:
В C++ оператор ... используется в блоках обработки исключений catch, а в C++11 — для шаблонов с переменным числом аргументов.
Типа только в 2011+ версиях будет работать?
0
DrOffset
7377 / 4454 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
19.08.2014, 09:10 #42
Цитата Сообщение от Izual Посмотреть сообщение
Типа только в 2011+ версиях будет работать?
Ага, начиная с VS 2013 или VS 2012 с последним обновлением. Как я уже говорил, это С++11 (действующий стандарт С++), а в VS достаточно инертно добавляют его поддержку (таблица поддержки возможностей на MSDN), в GCC и Clang давно все реализовано.
Кстати на С стандарт тоже обновился и тоже в 2011 году.
0
Izual
94 / 119 / 6
Регистрация: 13.11.2012
Сообщений: 1,556
19.08.2014, 10:33  [ТС] #43
Да заработало (установил VS 2013). Только теперь всё же остался вопрос с возвращяемым значением, оно не во всех функциях будет int. Как я понял из void* в int только warning, а вот уже даже с float будет error.
Прототип через шаблон функции, который предложил StailGot можно как то привести к динамическому использованию возвращяемого результата? (чтоб и double, и многие другие работали?)

Добавлено через 20 минут
П.С. Поясню сразу, что таблица с значениями у меня будет, т.е. я буду заранее знать какой тип вводить и выводить.
Например:
WINUSERAPI int WINAPI MessageBoxA(HWND,LPCSTR,LPCSTR,UINT);
HMENU WINAPI LoadMenuA(HINSTANCE,LPCSTR);
WINUSERAPI HWND WINAPI SetActiveWindow(HWND);
Имея такую таблицу, я хотел бы имея структуру (с "вложенными" union и enum) вида:
C++
1
2
3
4
5
6
7
8
9
10
11
12
typedef enum { BOOL,INT,FLOAT,STR } vtr;
struct var
{
    vtr t;//тип переменной
    union
    {
        bool b;
        int i;
        float f;
        char *s;
    }d;//данные переменной
};
просто исходя из типа переменной (v[i].t) задать в функции возвращяемое значение.

Да и ещё меня инетересует, можно ли исходя из типа вызова с помощью каких нибудь директив указывать использование _stdcall, например хотел было сделать так:
C++
1
#define WINAPI _stdcall
Но не работает =)

Добавлено через 5 минут
Подумалось, по пункту возвращяемого значения...
Ведь я могу изменить функцию:
C++
1
int call( vtr v, void * fun, Args ... args)
и в соответствии с типом сделать (что конешно вот меня не радует прототипы вызова для всех возможных возвращяемых значений... Примерно:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
switch(v):
{
case INT:
 using func_type = int( _stdcall *)( Args... ); // выведем тип функции по ее аргументам
 return ( (func_type)fun ) ( args... );
break;
case FLOAT:
 using func_type = float( _stdcall *)( Args... ); // выведем тип функции по ее аргументам
 return ( (func_type)fun ) ( args... );
break;
...
}
}
0
ForEveR
В астрале
Эксперт С++
7983 / 4742 / 321
Регистрация: 24.06.2010
Сообщений: 10,547
Завершенные тесты: 3
19.08.2014, 15:17 #44
Izual,
Цитата Сообщение от Izual Посмотреть сообщение
и в соответствии с типом сделать (что конешно вот меня не радует прототипы вызова для всех возможных возвращяемых значений...
Только так скорее всего. Ведь для того, чтобы вызвать функцию нам нужно знать ее тип и если аргументы еще можно вывести неявно, то возвращаемый тип без сигнатуры не узнать.
0
Izual
94 / 119 / 6
Регистрация: 13.11.2012
Сообщений: 1,556
19.08.2014, 15:27  [ТС] #45
Цитата Сообщение от ForEveR Посмотреть сообщение
Ведь для того, чтобы вызвать функцию нам нужно знать ее тип и если аргументы еще можно вывести неявно, то возвращаемый тип без сигнатуры не узнать.
Вы не поняли, у меня есть список функций, мне надо упростить вызов, чтоб не писать ~30 разных по возвратному значению прототипов. Я пробовал с void * из предыдущего примера, но void* работает только с <= 32 бита, а это мало, мне надо больше.
Может есть какой то способ динамического приведения типа или что то вроде этого, просто хочется один раз написать прототип и не париться. Я хочу так:
C++
1
2
3
4
5
int call( vtr vtype, void * fun, Args ... args)
{
 using func_type = vtype( _stdcall *)( Args... ); // выведем тип функции по ее аргументам
 return ( (func_type)fun ) ( args... );
}
Чтобы один этот прототип разпростронялся на все виды функций. vtr vtype это и будет конкретный тип, ну у меня в виде enum это сделано, хотя я думаю что это не подойдёт, ну может как то по другому можно..
0
19.08.2014, 15:27
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
19.08.2014, 15:27
Привет! Вот еще темы с ответами:

вызов функции main() - C++ Builder
хочу сделать чтоб в случае ошибки функция main() заново вызывалать(строка 30) при вводе неверного символа программа закрывается а нужно...

Вызов функции из DLL с AnsiString - C++ Builder
Можно ли вызывать функцию из dll, в качестве параметра которой будет AnsiString и возвращает значение AnsiString? CodeGuard ругается. Не...

Вызов функции из другого h или cpp - C++ Builder
Подскажите как правильно вызвать функцию из другого h или cpp использующего глобальные переменные из головного модуля и взаимодействуюшего...

Вызов функции внутри другой функции с передачей локальной переменной по ссылке - C++
Столкнулся с очень с интересной проблемой. Можно ли так делать? #include &lt;iostream&gt; using std::cout; void f(const int &amp;ref){...


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

Или воспользуйтесь поиском по форуму:
45
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.