如何从Python数组中读取字符

2024-05-12 19:35:47 发布

您现在位置:Python中文网/ 问答频道 /正文

更新:我在马克·托洛宁的帮助下解决了这个问题。解决方法如下(但有一件事我很困惑):

我从下面Mark Tolonen的答案(UTF-8)中显示的编码字符串开始:

CA_f1 = (ctypes.c_char_p * len(f1))(*(name.encode() for name in f1))

关闭优化后,我总是在条目时将rcx存储到内存变量中。在程序的后面,当我需要使用rcx中的指针时,我从内存中读取它。这只适用于单个指针,但不适用于访问下面所示的指针数组Mark Tolonen;这可能是因为它是一个指针数组,而不仅仅是一个指针。如果我在进入时将rcx存储到r15中,那么它确实有效,在程序的下游,它是这样工作的:

^{pr2}$

这不是问题,因为我通常在寄存器中存储尽可能多的变量;有时寄存器不够,所以我不得不求助于在内存中存储一些变量。现在,在处理字符串时,我将始终保留r15来保存在rcx中传递的指针(如果它是指针数组)。在

你知道内存位置为什么不工作吗?在

****答案结束****

我不熟悉NASM中的字符串处理,我正在从ctypes传递一个字符串。使用以下Python函数从文本文件(Windows.txt)读取字符串数据:

with open(fname, encoding = "utf8") as f1:
        for item in f1:
            item = item.lstrip()
            item = item.rstrip()
            return_data.append(item)
    return return_data

txt文件包含名字和姓氏的列表,用换行符分隔。在

我使用ctypes传递一个指向NASM dll的c_char_p指针。指针的创建方式如下:

CA_f1 = (ctypes.c_char_p * len(f1))()

visualstudio确认它是一个指向50个名称长度的字节字符串的指针,这可能是问题所在,我需要的是字节,而不是列表元素。然后我使用以下ctypes语法传递它:

CallName.argtypes = [ctypes.POINTER(ctypes.c_char_p),ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_double)]

更新:在传递字符串之前,现在我将列表转换为如下字符串:

f1_x = ' '.join(f1)

现在VS显示了一个指向558字节字符串的指针,这是正确的,但是我仍然不能读取一个字节。在

在我的NASM程序中,我使用以下代码将随机字节读入al进行测试:

lea rdi,[rel f1_ptr]
mov rbp,qword [rdi] ; Pointer
xor rax,rax
mov al,byte[rbp+1]

但rax中的返回值是0。在

如果我像这样创建一个本地字符串缓冲区:

name_array: db "Margaret Swanson"

我可以这样读:

mov rdi,name_array
xor rax,rax
mov al,[rdi]

但不是从传递到dll的指针。在

下面是NASM中一个简单、可重复的示例的完整代码。在将它传递给NASM之前,我检查了随机字节,它们是我所期望的,所以我不认为这是编码。在

[BITS 64]
[default rel]

extern malloc, calloc, realloc, free
global Main_Entry_fn
export Main_Entry_fn
global FreeMem_fn
export FreeMem_fn

section .data align=16
f1_ptr: dq 0
f1_length: dq 0
f2_ptr: dq 0
f2_length: dq 0
data_master_ptr: dq 0

section .text

String_Test_fn:
;______

lea rdi,[rel f1_ptr]
mov rbp,qword [rdi]
xor rax,rax
mov al,byte[rbp+10]
ret

;__________
;Free the memory

FreeMem_fn:
sub rsp,40
call free
add rsp,40
ret

; __________
; Main Entry

Main_Entry_fn:
push rdi
push rbp
mov [f1_ptr],rcx
mov [f2_ptr],rdx

mov [data_master_ptr],r8
lea rdi,[data_master_ptr]
mov rbp,[rdi]
xor rcx,rcx
movsd xmm0,qword[rbp+rcx]
cvttsd2si rax,xmm0
mov [f1_length],rax
add rcx,8
movsd xmm0,qword[rbp+rcx]
cvttsd2si rax,xmm0
mov [f2_length],rax
add rcx,8

call String_Test_fn

pop rbp
pop rdi
ret

更新2:

在答复请求时,下面是要使用的ctypes包装:

def Read_Data():

    Dir= "[FULL PATH TO DATA]"

    fname1 = Dir + "Random Names.txt"
    fname2 = Dir + "Random Phone Numbers.txt"

    f1 = Trans_02_Data.StrDataRead(fname1)
    f2 = Trans_02_Data.StrDataRead(fname2)
    f2_Int = [  int(numeric_string) for numeric_string in f2]
    StringTest_asm(f1, f2_Int)

def StringTest_asm(f1,f2):

    f1.append("0")

    f1_x = ' '.join(f1)
    f1_x[0].encode(encoding='UTF-8',errors='strict')

    Input_Length_Array = []
    Input_Length_Array.append(len(f1))
    Input_Length_Array.append(len(f2*8))

    length_array_out = (ctypes.c_double * len(Input_Length_Array))(*Input_Length_Array)

    CA_f1 = (ctypes.c_char_p * len(f1_x))() #due to SO research
    CA_f2 = (ctypes.c_double * len(f2))(*f2)
    hDLL = ctypes.WinDLL("C:/NASM_Test_Projects/StringTest/StringTest.dll")
    CallName = hDLL.Main_Entry_fn
    CallName.argtypes = [ctypes.POINTER(ctypes.c_char_p),ctypes.POINTER(ctypes.c_double),ctypes.POINTER(ctypes.c_double)]
    CallName.restype = ctypes.c_int64

    Free_Mem = hDLL.FreeMem_fn
    Free_Mem.argtypes = [ctypes.POINTER(ctypes.c_double)]
    Free_Mem.restype = ctypes.c_int64
    start_time = timeit.default_timer()

    ret_ptr = CallName(CA_f1,CA_f2,length_array_out)

    abc = 1 #Check the value of the ret_ptr, should be non-zero   

Tags: 字符串lenctypesf2f1raxfndouble
1条回答
网友
1楼 · 发布于 2024-05-12 19:35:47

您的名字读取代码将返回Unicode字符串列表。下面将把Unicode字符串的列表编码成一个字符串数组,传递给一个使用POINTER(c_char_p)的函数:

>>> import ctypes
>>> names = ['Mark','John','Craig']
>>> ca = (ctypes.c_char_p * len(names))(*(name.encode() for name in names))
>>> ca
<__main__.c_char_p_Array_3 object at 0x000001DB7CF5F6C8>
>>> ca[0]
b'Mark'
>>> ca[1]
b'John'
>>> ca[2]
b'Craig'

如果ca作为第一个参数传递给函数,则该数组的地址将位于rcxx64 calling convention。下面的C代码及其反汇编显示了VS2017 Microsoft编译器如何读取它:

DLL代码(test.c)

^{pr2}$

反汇编(编译优化以保持简短,我的评论已添加)

^{3}$

Python代码(测试.py)

from ctypes import *

dll = CDLL('test')
dll.func.argtypes = POINTER(c_char_p),
dll.restype = c_int

names = ['Mark','John','Craig']
ca = (c_char_p * len(names))(*(name.encode() for name in names))
print(hex(dll.func(ca)))

输出:

0x4d4a43

这是正确的ASCII码'M'、'J'和'C'。在

相关问题 更多 >