ctypes获取扩展模块中函数的返回值

ctypes获取返回值

我们前面已经看到了,通过ctypes像扩展模块中的函数传参时是没有问题的,但是我们如何拿到返回值呢?我们之前都是使用printf直接打印的,但是这样显然不行,我们肯定是要拿到返回值去做一些别的事情的。那么我们看看如何使用ctypes获取函数的返回值。

获取整型返回值

int test1(int a, int b)
{
    int c;
    c = a + b;
    return c;
}

void test2()
{

}

我们定义了两个函数,下面编译成dll文件,dll文件名叫做mmp.dll

from ctypes import *

lib = CDLL("./mmp.dll")
print(lib.test1(25, 33))  # 58
print(lib.test2())  # 125387149

我们看到对于test1的结果是正常的,但是对于test2来说即便返回的是void,在python中依旧会得到一个整型,但是这个结果肯定是不正确的。不过对于整型来说,是完全没有问题的。

当然我们后面还会遇到一个问题,这里提前说一下。扩展模块中的函数不要说返回void,即便返回一个char *,那么在python中得到的依旧是一个整型。这个是不同语言的类型不同造成的,正如我们传递参数一样,需要使用ctypes转化一下,那么在获取返回值的时候,也需要提前使用ctypes指定一下返回值到底是什么类型,只有这样才能拿到扩展模块中函数的正确的返回值。

获取字符数组返回值

#include <wchar.h>

char * test1()
{
    char *s = "hello satori";
    return s;
}

wchar_t * test2()
{
    //遇到wchar_t的时候,一定要导入wchar.h头文件
    wchar_t *s = L"憨八嘎";
    return s;
}

我们定义了两个函数,一个返回char *,一个返回wchar_t *。

from ctypes import *

lib = CDLL("./mmp.dll")
# 我们看到神奇的事情发生了,我们在扩展模块中返回的是一个字符数组的首地址,我们希望拿到指向的字符串
# 然而python拿到的确是一个整型,而且一看感觉这像是一个地址。如果是地址的话那么从理论上讲是对的,返回地址、获取地址
print(lib.test1())  # 1801207808
# 但我们希望的是获取地址指向的字符数组,所以我们需要指定一下返回的类型
# 指定为c_char_p,告诉ctypes我们不要地址,而是要通过这个地址获取其指向的字符数组
lib.test1.restype = c_char_p
# 此时就没有问题了
print(lib.test1())  # b'hello satori'

# 同理对于unicode也是一样的,如果不指定类型,得到的依旧是一个整型
lib.test2.restype = c_wchar_p
print(lib.test2())  # 憨八嘎

因此我们就将python中的类型和C语言中的类型通过ctypes关联起来了,我们传参的时候需要转化,同理获取返回值的时候也要使用ctypes来声明一下类型。因为默认python调用扩展模块的函数返回的都是整型,至于返回的整型的值到底是什么?从哪里来的?我们不需要关心,你可以理解为地址、或者某块内存的脏数据,但是不管怎么样,结果肯定是不正确的(如果函数返回的就是整形除外)。因此我们需要提前声明一下返回值的类型。声明方式:

lib.CFunction.restype = ctypes类型

我们说lib就是ctypes调用dll或者so得到的扩展模块,而里面的函数就相当于是一个个的CFunction,然后设置内部的restype(返回值类型),就可以得到正确的返回值了。另外即便返回值设置的不对,比如:test1返回一个char *,但是我们将类型设置为c_float,调用的时候也不会报错而且得到的也是一个float,但是这个结果肯定是不对的。

from ctypes import *

lib = CDLL("./mmp.dll")
lib.test1.restype = c_char_p
print(lib.test1())  # b'hello satori'

# 设置为c_float
lib.test1.restype = c_float
# 获取了不知道从哪里来的脏数据
print(lib.test1())  # 2.5420596244190436e+20

# 另外ctypes调用还有一个特点
lib.test2.restype = c_wchar_p
print(lib.test2(123, c_float(1.35), c_wchar_p("呼呼呼")))  # 憨八嘎
# 我们看到test2是不需要参数的,如果我们传了那么就会忽略掉,依旧能得到正常的返回值
# 但是不要这么做,因为没准就出问题了,所以还是该传几个参数就传几个参数

获取浮点型返回值

下面我们来看看浮点类型的返回值怎么获取,当然方法和上面是一样的。

#include <math.h>

float test1(int a, int b)
{
    float c;
    c = sqrt(a * a + b * b);
    return c;
}
from ctypes import *

lib = CDLL("./mmp.dll")

# 得到的结果是一个整型,默认都是整型。
# 我们不知道这个整型是从哪里来的,就把它理解为地址吧,但是不管咋样,结果肯定是不对的
print(lib.test1(3, 4))  # 1084227584

# 我们需要指定返回值的类型,告诉ctypes返回的是一个float
lib.test1.restype = c_float
# 此时结果就是对的
print(lib.test1(3, 4))  # 5.0

# 如果指定为double呢?
lib.test1.restype = c_double
# 得到的结果也有问题,总之类型一定要匹配
print(lib.test1(3, 4))  # 5.356796015e-315

# 至于int就不用说了,因为默认就是int。所以和第一个结果是一样的
lib.test1.restype = c_int
print(lib.test1(3, 4))  # 1084227584

所以类型一定要匹配,该是什么类型就是什么类型。即便扩展模块中返回的是float,我们在python中通过ctypes也要指定为float,而不是指定为double,尽管都是浮点数并且double的精度还更高,但是结果依旧不是正确的。至于整型就不需要关心了,但即便如此,int、long也不要混用,而且也建议传参的时候进行转化。

原文地址:https://www.cnblogs.com/traditional/p/12240344.html

时间: 2024-10-06 02:57:51

ctypes获取扩展模块中函数的返回值的相关文章

关于 Shell中函数的返回值 问题

# !/bin/sh sum() { echo $(($1+$2)) return $(($1-$2)) } sum $1 $2 c=$(sum $1 $2) echo $? echo $c 执行命令:./bashTest 11 1 运行结果是: 12 -- sum $1 $2的结果 10 -- echo $?的结果,因为return的值为10 12 --  echo $c的结果,值为12,所以c并不会被附上return的值,echo $c时调用了sum函数,所以打印了12 我们对shell中的

获取JavaScript异步函数的返回值

今天研究一个小问题: 怎么拿到JavaScript异步函数的返回值? 1.错误尝试 当年未入行时,我的最初尝试: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <script> function getSomething() {  var r = 0;  setTimeout(function() {  r = 2;  }, 10);  return r; } function compute() {  var x = getSomething();  alert

关于JS中函数的返回值的一点死思考

在Javascript中,函数总是会有一个返回值.即使我们没有显示的使用 "return",程序也会隐式的返回一个 "undefined". 通过下面的小demo即可理解. demo1 function fn(){ return 1; } fn(); 运行结果:1 demo2 function fn(){ console.log(1); } fn(); 运行结果:1 undefined

js 中 函数的返回值问题

var result=''; function searchByStationName( address ) { // map.clearOverlays();//清空原来的标注 var keyword = address ; localSearch.setSearchCompleteCallback(function (searchResult) { var poi = searchResult.getPoi(0); result = poi.point.lng + "," + po

Swift2.0语言教程之函数的返回值与函数类型

Swift2.0语言教程之函数的返回值与函数类型 Swift2.0中函数的返回值 根据是否具有返回值,函数可以分为无返回值函数和有返回值函数.以下将会对这两种函数类型进行讲解. Swift2.0中具有一个返回值的函数 开发者希望在函数中返回某一数据类型的值,必须要在函数声明定义时为函数设定一个返回的数据类型,并使用return语句进行返回.其中,return语句的一般表示形式如下: return 表达式 其中,表达式可以是符合Swift标准的任意表达式.而具有返回值的函数声明定义形式如下: fu

ctypes给扩展模块中的函数传递回调函数

C语言中的回调函数 什么是回调函数我就不介绍了,我们先来看看C语言中如何使用回调函数. 函数指针 不过在看回调函数之前,我们先看看如何把一个函数赋值给一个变量.准确的说,是让一个指针指向一个函数,这个指针叫做函数指针.通常我们说的指针变量是指向一个整型.字符型或数组等变量,而函数指针是指向函数.函数指针可以像一般函数一样,用于调用函数.传递参数. #include <stdio.h> int add(int a, int b){ int c; c = a + b; return c; } in

shell获取函数的返回值

背景:定义了一个函数,比对本地和线上服务器集群数量差别,想要获取不同集群的个数.shell和其他语言的函数返回值还是差别挺大的. 定义一个函数 functionname(){ 操作内容 echo 输出内容 return 返回值 #返回值可有可不有 } 获得函数的返回值 1.函数默认是将标准输出传递出来,不是返回值. 所以如果直接调用functionname,实际上是将输出传递回来 例如: a=`functionname` 将函数functionname的标准输出传递给a 2.调用函数不需要加()

自定义函数中的参数返回值 “-&gt; (Int -&gt; Int)”的问题

func makeIncrementer() -> (Int -> Int) { func addOne(number: Int) -> Int { return 1 + number } return addOne } var increment = makeIncrementer() println(increment(7)) 这里为什么要写两个 Int->Int 这里是返回值是参数,左边是参数,右边是返回值的意思. 自定义函数中的参数返回值 "-> (Int

关于PHP中eval函数的返回值

关于eval 的概念就是把字符串作为PHP代码执行.但是关于其返回值,有时候容易出错. 如下面定义一个函数 function get_func_type(){ return array(1=>'字符串处理','2'=>'数组处理'); } 你能正确说出例1,例2,例3的执行结果吗? 例1 $p=eval('get_func_type();'); trace($p); 例2 $p=eval('return get_func_type();'); trace($p); 例3 eval('$p=ge