Если возвращаемый тип действительно неизвестен или не имеет значения, вы можете использовать void
в определении функции, или если это любой указатель, вы можете использовать void *
, но если функция находится в C-кодированной DLL и вы будете использовать его в коде на C++, тогда вы можете использовать и делиться почти всеми типами, определенными в вашем коде на C, потому что C++ - это надмножество C.
При этом я подготовил небольшой пример со структурой под названием PyObject
совместно используемых в коде C и C++.
Чтобы сделать это, лучше создать заголовок с общими типами/определений:
#ifndef PYOBJECT_DLL_H
#define PYOBJECT_DLL_H
#ifdef __cplusplus
extern "C" {
#endif
// Common structure definition
typedef struct PyObject{
int field1;
char *field2;
} PyObject;
// Public function pointer type declaration
typedef PyObject *(*__stdcall getPyObject_t)(int arg1, const char *arg2);
#ifdef __cplusplus
}
#endif
#endif // PYOBJECT_DLL_H
Давайте предположим, что код C с экспортируемой функцией является чем-то вроде:
#include "pyobject.h"
#include <stdlib.h>
#ifdef __cplusplus
extern "C"
#endif
__declspec(dllexport) PyObject * getPyObject(int arg1, char *arg2);
PyObject *getPyObject(int arg1, char *arg2){
PyObject *obj = (PyObject *)malloc(sizeof(PyObject));
obj->field1 = arg1;
obj->field2 = arg2;
return obj;
}
Наконец, код C++ с использованием функции и данных, созданных в библиотеке, будет:
#include "pyobject.h"
#include <iostream>
#include <windows.h>
int main() {
HINSTANCE dll = LoadLibrary("pyobject.dll");
if (dll == NULL) {
std::cerr << "Cannot open pyobject.dll. Error: " << GetLastError() << "\n";
return 1;
}
getPyObject_t getPyObject = (getPyObject_t) GetProcAddress(dll, "getPyObject");
if (getPyObject == NULL) {
std::cerr << "Cannot locate 'getPyObject' function in dll. Error: " << GetLastError() << "\n";
FreeLibrary(dll);
return 2;
}
PyObject *obj = getPyObject(3, "test");
std::cout << "PyObject == { field1: " << obj->field1 << ", field2: \"" << obj->field2 << "\"}\n";
FreeLibrary(dll);
return 0;
}
Редактировать
Как @raymondchen отметил в своем комментарии, игнорируя тип возвращаемого значения, когда функция C возвращает большой агрегат (например, struct), это не очень хорошо, потому что функция C ожидает, что у вызывающего уже было зарезервированное пространство стека для хранения возвращенного агрегата, но если вызывающий объект обрабатывает функцию как void
или что-то еще, тогда компилятор не сохранит это пространство, непредсказуемые эффекты (возможно, заканчивающиеся ошибкой ошибки сегментации).
Чтобы избежать этого, всегда лучше определять правильный тип как в кодах C и C++ (или в общем заголовке), особенно когда функция C возвращает агрегат.
Что бы вы ожидали, если вы не знаете тип возврата? Способ вызова функции (соглашение о вызове) зависит от типа возвращаемого значения. – jtbandes
Плохая новость заключается в том, что если вы не знаете тип возврата во время компиляции, это * невозможно * без фрагмента рукописного языка ассемблера. Хорошей новостью является то, что кто-то уже подготовил для вас язык ассемблера: [libffi] (https://sourceware.org/libffi/). – zwol
Знаете ли вы тип возврата во время выполнения? –