【问题标题】:cython structure, string from python to cythoncython 结构,从 python 到 cython 的字符串
【发布时间】:2017-08-04 09:16:01
【问题描述】:

我想按照下面的操作将 python 对象转换为 cython 结构,但它不会将 simres[1] 的值分配给 resulta[x].cpt1

cdef struct resultaStructure:
    double score
    char **cpt1

simRes = [1.0,
['http://bioontology.org/projects/ontologies/fma/fmaOwlDlComponent_2_0#Abdomen', 
'Abdomen']]
cdef x = 0 
cdef resultaStructure *resulta = <resultaStructure *> malloc(sizeof(resultaStructure)*labelsSourceTaille)

resulta[x].score = simRes[0]
print("score : ",resulta[0].score)

resulta[x].cpt1 = <char**> malloc (sizeof (char**)*2)
print('2')
resulta[x].cpt1[0] = <char*> malloc (sizeof (char)*simRes[1][0].__len__()+1)
print('3')
resulta[x].cpt1[1] = <char*> malloc (sizeof (char)*simRes[1][1].__len__()+1)
print('4')
resulta[x].cpt1[0] = <char*> simRes[1][0]
print('5')
resulta[x].cpt1[1] = <char*>  simRes[1][1]
print('6')

print("cpt1 0 : ",resulta[0].cpt1[0])
print("cpt1 1 : ",resulta[0].cpt1[1])

这是结果

('score :', 1.0)

2

3

4

【问题讨论】:

    标签: python c cython


    【解决方案1】:

    问题和 OP 答案中的代码存在严重问题,从长远来看可能会导致程序崩溃。

    1)

    resulta[x].cpt1 = <char**> malloc (sizeof (char**)*2)
    

    cpt1 是一个指向(一个数组)char 指针的指针。因此它应该被分配为

    resulta[x].cpt1 = <char*> malloc (sizeof (char*)*2)
    

    (更好的是,如果长度始终为2,则在结构定义中分配char *cpt1[2],您不需要malloc。)

    这不太可能导致真正的问题,因为所有指针的大小都相同,但它仍然是错误的。

    2)(真正的问题部分a)

    resulta[x].cpt1[0] = <char*> malloc (sizeof (char)*simRes[1][0].__len__()+1)
    # ...
    resulta[x].cpt1[0] = <char*>some_python_string
    

    在这里你分配了一些内存,如果你倾向于让指针指向 Python 字符串所拥有的不同内存区域,那么你会立即忘记你分配的内存。您做的是将数据从 Python 字符串复制到分配的内存中。

    3)(真正的问题部分b)

    str1 = simRes[1][0].encode('UTF-8')
    resulta[x].cpt1[0] = <char*> str1
    

    cpt1[0] 指向的内存归str1 所有。如果str1 在您使用完结构之前被释放,那么该结构指向无效内存,您的程序将崩溃,或者读取一些稍后分配的随机数据,或者其他一些坏事。

    如果您可以保证 str1 将比您的结构寿命更长(例如,您的结构被用作一个 C 函数调用的参数),那么这是可以的,但在一般情况下可能不是。

    解决方法是将内容或str1复制到你新分配的内存中:

    resulta[x].cpt1[0] = <char*> malloc (sizeof (char)*len(simRes[1][0])+1)
    strcpy(resulta[x].cpt1[0],str1)
    

    (另外,你还记得freemalloced 的所有记忆,对吧?)

    【讨论】:

    • 谢谢你,你说得很清楚。这是一个我花了一些时间解决的问题,但正如你所说,它可能会因为你提到的问题而崩溃。第二点可以指向python内存,用于没有gil进程吗?,因为我的目的是使用cython并行没有gil。
    • 在没有 GIL 的情况下可以指向 Python 内存。在释放 GIL 之前,请确保您的线程持有对内存的引用。您要小心确保您的其他线程在查看时不会更改完全相同的内存,否则您可能会得到令人困惑的结果。 (尽管有多个线程更改同一数组的不同元素是可以的并且很常见)。字符串应该是不可变的,所以它们不应该被改变,这应该是安全的。
    【解决方案2】:

    解决方案是在赋值之前对python字符串进行如下编码,

    str1 = simRes[1][0].encode('UTF-8')
    resulta[x].cpt1[0] = <char*> str1
    print('5')
    str2 = simRes[1][1].encode('UTF-8')
    resulta[x].cpt1[1] = <char*> str2
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-10
      • 1970-01-01
      • 1970-01-01
      • 2013-07-04
      • 2014-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多