CFFI-将结构体与#ifdef一起使用

时间:2018-09-05 08:23:10

标签: python python-cffi cffi

目前,我正在将一些现有的C代码包装到Python中。它与CFFI配合得很好,但是我没有最后一件事。

如何处理“ #ifdef”语句?

假设我在c中有此结构:

typedef struct can_config_tag
{
    char_t type[4];
    uint16_t module_nr;
#ifdef CAN_MON
    uint16_t rx_main_mon;
#endif
    byte_t rx_obj;
}

我不明白如何处理这些“ #ifdef”语句。在文档中,我发现带有“ ...;”的内容但是我怎样才能访问结构的数据呢?

当尝试使用...并通过以下方式访问数据时:

can_config= ffi.new("can_config_tag *")
can_config.rx_main_mon = 2

我收到一条错误消息:

AttributeError: cdata 'struct can_config_tag*' has no field 'rx_main_mon'

那么在使用cffi时如何处理这些预处理程序指令是否有任何变通办法?提前谢谢。

1 个答案:

答案 0 :(得分:0)

问题在于ffi.cdef()不能给出依赖于预处理指令的结果,因为这些只有在以后调用C编译器时才知道。 (在离线构建的情况下,这可能是固定的,但这不是立即的。)

有两种可能的解决方法:

  1. 执行几个编译步骤。

  2. 不公开可选字段,而是添加自定义访问器函数。

对于1.,写这样的东西:

ffi_pre = FFI()
ffi_pre.cdef("#define CAN_MON_IS_DEFINED ...")
ffi_pre.set_source("_tmp_cffi", """
    #include <foo_mon.h>
    #ifdef CAN_MON
    #  define CAN_MON_IS_DEFINED 1
    #else
    #  define CAN_MON_IS_DEFINED 0
    #endif
""")
ffi_pre.compile()
from _tmp_cffi import ffi as ffi_tmp
can_mon = ffi_tmp.CAN_MON_IS_DEFINED

...然后编写其余代码,就像您已经拥有的一样,但是在某处使用if can_mon:作为Python代码,例如像这样在cdef中构建字符串:

"""
typedef struct can_config_tag
{
    char_t type[4];
    uint16_t module_nr;
""" + ("uint16_t rx_main_mon;" if can_mon else "") + """
    byte_t rx_obj;
};
"""

解决方案编号2是永远不要定义字段rx_main_mon,而要添加C函数来读取和写入该字段(如果定义了该字段):

ffi.cdef("""
typedef struct can_config_tag
{
    char_t type[4];
    uint16_t module_nr;
    byte_t rx_obj;
};
int my_read_rx_main_mon(struct can_config_tag *);
void my_write_rx_main_mon(struct can_config_tag *, int value);
""")
ffi.set_source("somename", """
#include <foomon.h>
static int my_read_rx_main_mon(struct can_config_tag *p)
{
#ifdef CAN_MON
    return p->rx_main_mon;
#else
    return -1;
#endif
}
static void my_write_rx_main_mon(struct can_config_tag *p, int value)
{
#ifdef CAN_MON
    p->rx_main_mon = value;
#endif
}
""")