相当于c的Cython定义#define myfunc(node x,...)SetNode(x.getattributeNode(),__ VA_ARGS__) [英] Cython equivalent of c define #define myfunc(node x,...) SetNode(x.getattributeNode(),__VA_ARGS__)
问题描述
Cython等效于c define
Cython equivalent of c define
#define myfunc(Node x,...) SetNode(x.getattributeNode(),__VA_ARGS__)
我有一个ac api SetNode,它的第一个参数是结构类型为node的节点,并且为N个变量(N是从0到N的变量)
I have a c api SetNode which takes first argument a node of struct type node and N variables (N is variable number from 0-N)
这是解决此类问题的ac示例
here is a c example to solve such problum
exampleAPI。 c
exampleAPI.c
#include<stdarg.h>
float sumN(int len,...){
va_list argp;
int i;
float s=0;
va_start(argp,len);
for(i=0;i<len;i++){
s+=va_arg(argp,int);
}
va_end(argp);
}
exampleAPI.h
exampleAPI.h
#include<stdarg.h>
float sumN(int len,...)
examplecode.c
examplecode.c
#include<stdarg.h>
#include"exampleAPI.h"
int len(float first,...){
va_list argp;
int i=1;
va_start(argp,first);
while(1){
if(va_arg(argp,float)==NULL){
return i
}
else{
i++;
}
}
va_end(argp);
}
#define sum(...) sumN(len(__VA_ARGS__),__VA_ARGS__)
现在调用
sum(1,2,3,4);
将返回 10.000000
sum(1.5,6.5);
将返回 8.00000
我需要一个cython替代品用于下面的c定义,而不是上面的示例
,因为我有一个C-API,它具有SetNode函数,该函数需要可变数量的参数,并且我想将其包装在cython中并从python调用
I need a cython alternative for bellow c definition and not above example because I have a C-API which has SetNode function which takes variable number of arguments and I want to wrap it in cython and call from python
#define myfunc(Node x,...) SetNode(x.getattributeNode(),__VA_ARGS__)
其中Node是在cython中定义的类,该类将ac stuct作为属性,而getattributeNode()是Node类的函数,该函数返回
here Node is a class defined in cython which holds a c stuct as attribute and getattributeNode() is a function of Node class which returns c struct that needs to be passed into C-API.
cdef extern "Network.h":
ctypedef struct node_bn:
pass
node_bn* SetNode(node_bn* node,...)
cdef class Node:
cdef node_bn *node
cdef getattributeNode(self):
return self.node
def setNode(self,*arg):
self.node=SetNode(self.node,*arg) # Error cannot convert python objects to c type
cdef extern from "stdarg.h":
ctypedef struct va_list:
pass
ctypedef struct fake_type:
pass
void va_start(va_list, void* arg)
void* va_arg(va_list, fake_type)
void va_end(va_list)
fake_type int_type "int"
cdef extern "Network.h":
ctypedef struct node_bn:
pass
node_bn* VSetNode(node_bn* node,va_list argp)
cdef class Node:
cdef node_bn *node
cdef getattributeNode(self):
return self.node
cpdef _setNode(self,node_bn *node,...):
cdef va_list agrp
va_start(va_list, node)
self.node=VSetNode(node,argp)
va_end(va_list)
def setNode(self,*arg):
self._setNode(self.node,*arg)
当参数列表为空时工作正常
works fine when argument list is empty
n = Node()
n.setNode() #This works
n.SetNode("top",1) # error takes exactly one argument given 3 in self._setNode(self.node,*arg)
如果
推荐答案
我不认为通过Cython(问题是告诉Cython对任意数量的参数执行什么类型的转换)。我最好的建议是针对这种特定情况使用标准库ctypes库,并将其余的都包装在Cython中。
I don't think it's easily done though Cython (the problem is telling Cython what type conversions to do for an arbitrary number of arguments). The best I can suggest is to use the standard library ctypes library for this specific case and wrap the rest in Cython.
为了举例说明,我使用了一个非常简单的求和函数。 va_sum.h包含:
For the sake of an example, I've used a very simple sum function. va_sum.h contains:
typedef struct { double val; } node_bn;
node_bn* sum_va(node_bn* node,int len, ...);
/* on windows this must be:
__declspec(dllexport) node_bn* sum_va(node_bn* node,int len, ...);
*/
和va_sum.c包含:
and va_sum.c contains:
#include <stdarg.h>
#include "va_sum.h"
node_bn* sum_va(node_bn* node,int len, ...) {
int i;
va_list vl;
va_start(vl,len);
for (i=0; i<len; ++i) {
node->val += va_arg(vl,double);
}
va_end(vl);
return node;
}
我已经编写了它,因此它将所有内容添加到结构中的字段中来证明您可以毫不费力地传递指向结构的指针。
I've written it so it adds everything to a field in a structure just to demonstrate that you can pass pointers to structures without too much trouble.
Cython文件为:
The Cython file is:
# definition of a structure
cdef extern from "va_sum.h":
ctypedef struct node_bn:
double val;
# obviously you'll want to wrap things in terms of Python accessible classes, but this atleast demonstrates how it works
def test_sum(*args):
cdef node_bn input_node;
cdef node_bn* output_node_p;
input_node.val = 5.0 # create a node, and set an initial value
from ctypes import CDLL, c_double,c_void_p
import os.path
# load the Cython library with ctypes to gain access to the "sum_va" function
# Assuming you've linked it in when you build the Cython module
full_path = os.path.realpath(__file__)
this_file_library = CDLL(full_path)
# I treat all my arguments as doubles - you may need to do
# something more sophisticated, but the idea is the same:
# convert them to the c-type the function is expecting
args = [ c_double(arg) for arg in args ]
sum_va = this_file_library.sum_va
sum_va.restype = c_void_p # it returns a pointer
# pass the pointers as a void pointer
# my c compiler warns me if I used int instead of long
# but which integer type you have to use is likely system dependent
# and somewhere you have to be careful
output_node_p_as_integer = sum_va(c_void_p(<long>&input_node),len(args),
*args)
# unfortunately getting the output needs a two stage typecast - first to a long, then to a pointer
output_node_p = <node_bn*>(<long>(output_node_p_as_integer))
return output_node_p.val
您需要将va_sum.c和Cython文件一起编译(例如通过添加源= ['cython_file.pyx','va_sum.c']
在setup.py中)
You need to compile your va_sum.c together with your Cython file (e.g. by adding sources = ['cython_file.pyx','va_sum.c']
in setup.py)
Ctypes可能比Cython慢一些(我认为每个调用都有合理的开销),并且将它们混合在一起很奇怪,但这至少应该让您在Cython中编写主包装,并使用ctypes来解决特定的限制
Ctypes is probably a bit slower than Cython (I think there's a reasonable overhead on each call), and it's odd to mix them, but this should at least let you write the main wrapper in Cython, and use ctypes to get round the specific limitation.
这篇关于相当于c的Cython定义#define myfunc(node x,...)SetNode(x.getattributeNode(),__ VA_ARGS__)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!