python पायथन ctypes cdll.LoadLibrary, किसी ऑब्जेक्ट को इंस्टेंट करता है, उसकी विधि निष्पादित करता है, निजी चर पता



windows (1)

मैंने c में एक dll लाइब्रेरी लिखी, vs2017 64-बिट के साथ संकलित की, और इसे python3.6 64-bit के साथ लोड करने का प्रयास किया। हालाँकि ऑब्जेक्ट के सदस्य चर का पता 32-बिट पर छोटा हो गया।

यहाँ मेरी sim.c फाइल है, जिसे sim.dll में संकलित किया गया है:

class Detector {
public:
    Detector();
    void process(int* pin, int* pout, int n);

private:
    int member_var;
};

Detector::Detector()
{
    memset(&member_var, 0, sizeof(member_var));
    myfile.open("addr_debug.txt");
    myfile << "member_var init address: " << &member_var << endl;
}
void Detector::process(int* pin, int* pout, int n);
{
    myfile << "member_var process address: " << &member_var << endl;
    myfile.close();
}

#define DllExport   __declspec( dllexport )  

extern "C" {
    DllExport Detector* Detector_new() { return new Detector(); }
    DllExport void Detector_process(Detector* det, int* pin, int* pout, int n)
    {
        det->process(pin, pout, n);
    }
}

यहाँ मेरी अजगर स्क्रिप्ट है:

from ctypes import cdll
lib = cdll.LoadLibrary(r'sim.dll')

class Detector(object):
    def __init__(self):
        self.obj = lib.Detector_new()

    def process(self,pin, pout, n):
        lib.Detector_process(self.obj,pin, pout, n)

detector = Detector()

n = 1024
a = np.arange(n, dtype=np.uint32)
b = np.zeros(n, dtype=np.int32)

aptr = a.ctypes.data_as(ctypes.POINTER(ctypes.c_int))
bptr = b.ctypes.data_as(ctypes.POINTER(ctypes.c_int))

detector.process(aptr, bptr, n)

यहां सदस्य का पता add__ebeb.txt में सदस्य है:

member_var init address:    0000025259E123C4
member_var process address: 0000000059E123C4

इसलिए इसे एक्सेस करने से मेमोरी एक्सेस एरर ट्रिगर होता है:

OSError: exception: access violation reading 0000000059E123C4

कुछ प्रयास मैंने इस मुद्दे को समझने की कोशिश की:

  • निजी के बजाय सार्वजनिक रूप से सदस्य_वर को परिभाषित करें, मदद नहीं, पता अभी भी छोटा है।
  • सदस्य चर को वैश्विक चर के रूप में परिभाषित करें, फिर पता ठीक है। इसलिए मुझे लगता है कि सदस्य_वर एड्रेस ट्रंकेशन या तो तब होता है जब ऑब्जेक्ट को अजगर पर लौटाते हैं, या ऑब्जेक्ट को वापस dll में पास करते हैं।

हमेशा (निश्चित रूप से) C में परिभाषित कार्यों के लिए argtypes और restype निर्दिष्ट करें , अन्यथा ( C89 शैली) वे int ( 32 बिट ) के लिए डिफ़ॉल्ट होंगे, जेनरेटिंग !!! अपरिभाषित व्यवहार !!! 64 बिट पर , यह ट्रंकेशन (जो वास्तव में आप अनुभव कर रहे हैं) में परिणाम हो सकता है।

इसके अलावा, जब मुद्दों में भाग लेते हैं, तो [Python 3.Docs] के बारे में मत भूलना : ctypes - Python के लिए एक विदेशी फ़ंक्शन लाइब्रेरी

नीचे यह आपके कोड का एक अनुकूलित संस्करण है।

डिटेक्टर

#include <stdio.h>
#include <memory.h>
#include <fstream>

#define C_TAG "From C"
#define PRINT_MSG_2SP(ARG0, ARG1) printf("%s - [%s] (%d) - [%s]:  %s: 0x%0p\n", C_TAG, __FILE__, __LINE__, __FUNCTION__, ARG0, ARG1)


using std::endl;

std::ofstream outFile;


class Detector {
    public:
        Detector();
        void process(int *pIn, int *pOut, int n);

    private:
        int m_var;
};


Detector::Detector() 
: m_var(0) {
    outFile.open("addr_debug.txt");
    outFile << "m_var init address: " << &m_var << endl;
    PRINT_MSG_2SP("&m_var", &m_var);
}

void Detector::process(int *pIn, int *pOut, int n) {
    outFile << "m_var process address: " << &m_var << endl;
    outFile.close();
    PRINT_MSG_2SP("&m_var", &m_var);
}


#define SIM_EXPORT __declspec(dllexport)

#if defined(__cplusplus)
extern "C" {
#endif

    SIM_EXPORT Detector *DetectorNew() { return new Detector(); }
    SIM_EXPORT void DetectorProcess(Detector *pDet, int *pIn, int *pOut, int n) {
        pDet->process(pIn, pOut, n);
    }
    SIM_EXPORT void DetectorDelete(Detector *pDet) { delete pDet; }

#if defined(__cplusplus)
}
#endif

कोडहोम :

import sys
from ctypes import CDLL, POINTER, \
    c_int, c_void_p
import numpy as np


sim_dll = CDLL("./sim.dll")

detector_new_func = sim_dll.DetectorNew
detector_new_func.restype = c_void_p

detector_process_func = sim_dll.DetectorProcess
detector_process_func.argtypes = [c_void_p, POINTER(c_int), POINTER(c_int), c_int]

detector_delete_func = sim_dll.DetectorDelete
detector_delete_func.argtypes = [c_void_p]


class Detector():
    def __init__(self):
        self.obj = detector_new_func()

    def process(self, pin, pout, n):
        detector_process_func(self.obj, pin, pout, n)

    def __del__(self):
        detector_delete_func(self.obj)


def main():
    detector = Detector()

    n = 1024
    a = np.arange(n, dtype=np.uint32)
    b = np.zeros(n, dtype=np.int32)

    aptr = a.ctypes.data_as(POINTER(c_int))
    bptr = b.ctypes.data_as(POINTER(c_int))

    detector.process(aptr, bptr, n)


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

नोट :

  • जैसा कि मैंने शुरुआत में कहा था, समस्या अर्गेटिप्स और रिस्टाइप निर्दिष्ट नहीं की जा रही थी (उदाहरण के लिए डिटेक्टर : कमेंट detector_new_func.restype = c_void_p , और आप फिर से समस्या में चलेंगे)
  • प्रश्न में कोड गायब भागों ( #include s, import s, ...) भी है, इसमें कुछ सिंटैक्स त्रुटियां भी हैं, इसलिए यह संकलन नहीं करता है, और इसलिए [SO] का पालन नहीं करता है : कैसे एक न्यूनतम बनाने के लिए, पूर्ण और सत्यापन योग्य उदाहरण (mcve) दिशानिर्देश। कृपया पूछते समय mcve होना सुनिश्चित करें
  • वह वस्तु जिसे आप आवंटित करते हैं ( new Detector() ), उसे भी निस्तारित किया जाना चाहिए (अन्यथा, यह एक मेमोरी रिसाव उत्पन्न करेगा), इसलिए मैंने एक फ़ंक्शन ( DetectorDelete - ऐसा करने के लिए) जोड़ा, जिसे पायथन ( डिटेक्टर ) डिटेक्टर से कहा जाता है नाशक
  • अन्य (नॉन क्रिटिकल) परिवर्तन (पहचानकर्ता का नाम बदलकर, थोड़ा सा रिफैक्टरिंग, मुद्रण के लिए stdout , ...)

आउटपुट :

(py35x64_tes1) e:\Work\Dev\\q052268294>"c:\Install\x86\Microsoft\Visual Studio Community\2015\vc\vcvarsall.bat" x64

(py35x64_test) e:\Work\Dev\\q052268294>dir /b
code.py
detector.cpp

(py35x64_test) e:\Work\Dev\\q052268294>cl /nologo /DDLL /EHsc detector.cpp  /link /DLL /OUT:sim.dll
detector.cpp
   Creating library sim.lib and object sim.exp

(py35x64_test) e:\Work\Dev\\q052268294>dir /b
code.py
detector.cpp
detector.obj
sim.dll
sim.exp
sim.lib

(py35x64_test) e:\Work\Dev\\q052268294>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" ./code.py
Python 3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32

From C - [detector.cpp] (28) - [Detector::Detector]:  &m_var: 0x0000020CE366E270
From C - [detector.cpp] (34) - [Detector::process]:  &m_var: 0x0000020CE366E270




ctypes