如何在ctypes中从C写入字符串缓冲区?

问题描述 投票:1回答:1

问题

我正在尝试使用ctypes在Python中使用C函数。函数reverse应该将stri的反向版本写入stro

rev.c:

#include <stddef.h>
/* length is the length of the string EXCLUDING the \0 terminator
*/
void reverse(char * stro, char * stri, size_t length)
{
    for(size_t i=0; i<length; i++) stro[i]=stri[length-1-i];
    stro[length]='\0';
}

Rev.朋友:

from ctypes import *

revlib = cdll.LoadLibrary("rev.so");
reverse = revlib.reverse
reverse.argtypes = [c_char_p, c_char_p, c_size_t]

hello = "HelloWorld"
stri = create_string_buffer(hello)
stro = create_string_buffer(b'\000' * (len(hello)+1))

reverse(stro, stri, len(stri))

print(repr(stri.value))
print(repr(stro.value))

我用gcc -o rev.so -shared -fPIC rev.c编译了c文件,调用了export LD_LIBRARY_PATH=.然后我尝试了上面的python脚本。这是输出:

$ python rev.py 
'HelloWorld'
''

我预计第二行是'dlroWolleH'。我避免使用白色空格以防万一它们可能导致问题。

我试过了什么

我用gcc rev.c -Wall -Wextra -std=c11 -pedantic编译了上面的c函数,它没有产生任何警告。

当我使用这个main函数时,该函数似乎有效:

int main() {
    char * str = "Hello, World";
    char o[100];
    reverse(o, str, strlen(str));
    puts(str);
    puts(o);
}

产生这个输出:

$ gcc rev.c; ./a.out 
Hello, World
dlroW ,olleH

为了尝试成功写入缓冲区,我尝试了这样的sscanf

libc = cdll.LoadLibrary("libc.so.6")
stri = create_string_buffer(100)
libc.sscanf("HelloWorld", "%s", stri)
print(repr(stri.value))

这打印出预期的结果。但我的功能似乎无法写入缓冲区。

我究竟做错了什么?

python c ctypes
1个回答
4
投票

问题其实很简单。当你使用create_string_buffer时,它会在字符串中添加一个null终止符。这意味着len(stri)将产生比len(hello)更大的结果。

解决方案正在改变

reverse(stro, stri, len(stri))

reverse(stro, stri, len(stri)-1)

这是一个演示,我将输入字符串更改为'Hello,World!':

$ python rev.py
'Hello, World!'
'!dlroW ,olleH'
© www.soinside.com 2019 - 2024. All rights reserved.