运行代码后,我只能访问数组的第一个结构,该结构在 c 中定义 外部文件中定义的函数。 我认为错误在于这一行:
engineLIB.get_files.restype = ctypes.POINTER(file)
其中仅将 restype 定义为“文件”而不是文件数组。
我无法找到此语法,所以我向你们寻求帮助。
提前谢谢了。
这是我的Python源代码:
import ctypes
engineLIB = ctypes.CDLL('./engine.so')
class file(ctypes.Structure):
_fields_ = [
("name", ctypes.c_char * 250),
("path", ctypes.c_char * 250),
("fileCnt", ctypes.c_int),
]
engineLIB.get_files.restype = ctypes.POINTER(file)
engineLIB.get_files.argtype = ctypes.c_char_p
path = input("Input path: ")
files = engineLIB.get_files(path.encode("utf-8"))
for i in range(2):
print(files[i].name)
print(files[i].path)
我尝试将 restype 定义为顶部定义的文件类的结构数组
正如我的评论中所述,看起来像是[SO]的重复:使用ctypes传递和获取C函数数组的问题(@CristiFati的答案)(尽管它是针对double而不是结构,并且还包含(额外的)双指针(**)内容),所以请务必阅读第 1st。
我还想强调[SO]:通过ctypes从Python调用的C函数返回不正确的值(@CristiFati的答案)(你有一个打字错误:argtypes)。
我准备了一个我猜你正在尝试的例子。
dll00.c:
#include <stdlib.h>
#include <string.h>
#if defined(_WIN32)
# define DLL00_EXPORT_API __declspec(dllexport)
#else
# include <dirent.h>
# define DLL00_EXPORT_API
#endif
#define MAXPATH 250
typedef struct {
char name[MAXPATH];
char path[MAXPATH];
int cnt;
} File, *PFile;
#if defined(__cplusplus)
extern "C" {
#endif
DLL00_EXPORT_API PFile getFiles(const char *path, int *pCount);
DLL00_EXPORT_API void dealloc(File *ptr);
#if defined(__cplusplus)
}
#endif
#if !defined(_WIN32)
PFile getFiles(const char *path, int *pCount)
{
DIR *pDir = NULL;
struct dirent *pEntry = NULL;
PFile ret = NULL;
int idx = 0;
if ((!pCount) || (!path)) {
return ret;
}
if (!(pDir = opendir(path))) {
*pCount = -1;
return ret;
}
*pCount = 0;
while ((pEntry = readdir(pDir))) {
++(*pCount);
}
closedir(pDir);
if (!(pDir = opendir(path))) {
*pCount = -1;
return ret;
}
*pCount += idx;
ret = calloc(*pCount, sizeof(File));
while ((pEntry = readdir(pDir))) {
strcpy(ret[idx].name, pEntry->d_name);
strcpy(ret[idx].path, path);
ret[idx].cnt = idx;
++idx;
}
closedir(pDir);
return ret;
}
#endif
void dealloc(File *ptr)
{
free(ptr);
}
code00.py:
#!/usr/bin/env python
import ctypes as cts
import sys
DLL_NAME = "./dll00.{:s}".format("dll" if sys.platform[:3].lower() == "win" else "so")
MAXPATH = 250 # @TODO - cfati: definitions must match the C ones
class File(cts.Structure):
_fields_ = (
("name", cts.c_char * MAXPATH),
("path", cts.c_char * MAXPATH),
("cnt", cts.c_int),
)
FilePtr = cts.POINTER(File)
def main(*argv):
dll = cts.CDLL(DLL_NAME)
getFiles = dll.getFiles
getFiles.argtypes = (cts.c_char_p, cts.POINTER(cts.c_int))
getFiles.restype = FilePtr
dealloc = dll.dealloc
dealloc.argtypes = (FilePtr,)
dealloc.restype = None
#path = input("Input path: ")
path = "."
count = cts.c_int(0)
files = getFiles(path.encode(), cts.byref(count))
print("Path [{:s}] has {:d} entries:".format(path, count.value))
for idx in range(count.value):
file = files[idx]
print("\nName: [{:s}]\nPath: [{:s}]\nCnt: {:d}\n".format(file.name.decode(), file.path.decode(), file.cnt))
dealloc(files)
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.\n")
sys.exit(rc)
注释:
当以指针形式返回数组(因为这就是函数返回的内容:结构数组)(缺少大小信息)时,有多种方法向调用者发出大小信号。我选择了最简单的一个:函数的附加(输出)参数。
C代码效率低下,它遍历目录两次(一次获取文件计数,第二次nd实际获取数据)。还有其他选择(在需要时增加数组大小),但代码会变得非常复杂,并且超出了问题范围
更多的错误处理不会有什么坏处
输出:
[cfati@cfati-5510-0:/mnt/e/Work/Dev/StackExchange/StackOverflow/q077368808]> . ~/sopr.sh ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [064bit prompt]> ls code00.py dll00.c [064bit prompt]> [064bit prompt]> gcc -fPIC -shared -o dll00.so dll00.c [064bit prompt]> ls code00.py dll00.c dll00.so [064bit prompt]> [064bit prompt]> python ./code00.py Python 3.10.12 (main, Jun 11 2023, 05:26:28) [GCC 11.4.0] 064bit on linux Path [.] has 5 entries: Name: [.] Path: [.] Cnt: 0 Name: [..] Path: [.] Cnt: 1 Name: [code00.py] Path: [.] Cnt: 2 Name: [dll00.c] Path: [.] Cnt: 3 Name: [dll00.so] Path: [.] Cnt: 4 Done.