使用ctypes和wchar_t时如何从C ++到python获取字符串?

时间:2018-05-17 15:41:11

标签: python c++ python-3.x ctypes

我可以:

  1. 从C ++获取一个整数并在python
  2. 中使用它
  3. 将一个python字符串(作为wchar_t)发送到C ++并用它做一些逻辑
  4. 我做不到 第2步反方向。

    这是我的C ++代码(使用C ++ 14将clion和cygwin编译为共享库)。

    #include <iostream>
    
    wchar_t aa[2];
    extern "C" {
        int DoA()
        {
            return 10;
        }
        int DoB(wchar_t  * in)
        {
            if (in[1] == 'a')
            {
                return 25;
            }
            return  30;
        }
    
        wchar_t * DoC()
        {
            aa[0] = 'a';
            aa[1] = 'b';
            return aa;
        }
    }
    

    这是我的python 3.6.1代码,它显示了我能做什么和不能做什么。那么我应该如何获取我的字符串并在python中使用它?我希望使用wstring_at的地址来获取值,但它不起作用。

    from ctypes import *
    import os.path
    print('Hello')
    
    itExist = os.path.exists('C:/Users/Daan/CLionProjects/stringproblem/cmake-build-release/cygstringproblem.dll')
    print(itExist)
    lib = cdll.LoadLibrary('C:/Users/Daan/CLionProjects/stringproblem/cmake-build-release/cygstringproblem.dll')
    print('dll loaded')
    
    A = lib.DoA()
    print(A)
    Bx = lib.DoB(c_wchar_p('aaa'))
    print(Bx)
    By = lib.DoB(c_wchar_p('bbb'))
    print(By)
    Ca = lib.DoC()
    print(Ca)
    print('Issue is coming')
    Cb = wstring_at(Ca,2)
    print(Cb)
    

    这是输出错误。

    Hello
    
    True
    
    dll loaded
    
    10
    
    25
    
    30
    
    -1659080704
    
    Issue is coming
    Traceback (most recent call last):
      File "ShowProblem.py", line 19, in <module>
        Cb = wstring_at(Ca,2)
      File "C:\Users\Daan\AppData\Local\Programs\Python\Python36\lib\ctypes\__init__.py", line 504, in wstring_at
        return _wstring_at(ptr, size)
    OSError: exception: access violation reading 0xFFFFFFFF9D1C7000
    

2 个答案:

答案 0 :(得分:1)

我在Linux上重现了您的问题并通过定义<script> $(document).ready(function(){$(".lstrev").magnificPopup({type:"ajax",mainClass:"mfp-fade",alignTop:"true",overflowY:"scroll",callbacks:{ajax:{closeBtnInside:"true",dataType:"html",cursor:"mfp-ajax-cur",tError:'<a href="%url%">The content</a> could not be loaded.'}}})}); </script> 函数的返回类型进行了更正:

DoC

我还动态分配了内存(某些Python专家可能对此发表评论,我猜这会导致内存泄漏):

from ctypes import *
print('Hello')

lib = cdll.LoadLibrary(PATH_TO_TOUR_LIB)
print('dll loaded')
# this line solved the issue for me
lib.DoC.restype = c_wchar_p

A = lib.DoA()
print(A)
Bx = lib.DoB(c_wchar_p('aaa'))
print(Bx)
By = lib.DoB(c_wchar_p('bbb'))
print(By)
Ca = lib.DoC()
print(Ca)
print('Issue is coming')
Cb = wstring_at(Ca,2)
print(Cb)

让我知道它是否适用于Windows。

答案 1 :(得分:1)

如果您设置了包装函数的.argtypes.restype,则可以更自然地调用它们。要处理输出字符串,如果在Python中分配缓冲区而不是使用全局变量,则它将是线程安全的,或者只返回一个宽字符串常量。这是为Microsoft编译器编写的示例:

<强> test.c的

#include <wchar.h>
#include <string.h>

__declspec(dllexport) int DoA(void) {
    return 10;
}

__declspec(dllexport) int DoB(const wchar_t* in) {
    if(wcslen(in) > 1 && in[1] == 'a') // Make sure not indexing past the end.
        return 25;
    return  30;
}

// This version good if variable data is returned.
// Need to pass a buffer of sufficient length.
__declspec(dllexport) int DoC(wchar_t* aa, size_t length) {
    if(length < 3)
        return 0;
    aa[0] = 'a';
    aa[1] = 'b';
    aa[2] = '\0';
    return 1;
}

// Safe to return a constant.  No memory leak.
__declspec(dllexport) wchar_t* DoD(void) {
    return L"abcdefg";
}

<强> test.py

from ctypes import *

# Set up the arguments and return type
lib = CDLL('test')
lib.DoA.argtypes = None
lib.DoA.restype = c_int  # default, but just to be thorough.
lib.DoB.argtypes = [c_wchar_p]
lib.DoB.restype = c_int
lib.DoC.argtypes = [c_wchar_p,c_size_t]
lib.DoC.restype = c_int
lib.DoD.argtypes = None
lib.DoD.restype = c_wchar_p

# Map to local namespace functions
DoA = lib.DoA
DoB = lib.DoB
DoD = lib.DoD

# Do some pre- and post-processing to hide the memory details.
def DoC():
    tmp = create_unicode_buffer(3)  # Writable array of wchar_t.
    lib.DoC(tmp,sizeof(tmp))
    return tmp.value  # return a Python string instead of the ctypes array.

print(DoA())
print(DoB('aaa'))
print(DoB('bbb'))
print(DoC())
print(DoD())

输出:

10
25
30
ab
abcdefg