在不知道返回类型的情况下,通过其地址调用C ++中的函数

时间:2016-12-22 04:48:48

标签: c++ c memory-address function-call

我想通过其地址从C ++ dll调用C函数。

我知道如何在这个单独的问题中知道返回类型的地方:Calling a function through its address in memory in c / c++

但是,如果我不知道返回类型,我该怎么办?我已经尝试过" typedef auto",但似乎你不能像那样使用auto。

1 个答案:

答案 0 :(得分:2)

如果返回类型确实未知或无关紧要,可以在函数定义中使用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函数返回聚合时。