更复杂的ctypes示例

这里我们将看一个更复杂的例子。首先考虑下面的C代码。

#include <stdio.h>
#include <stdlib.h>

struct double_row_element_t {
  double value;
  int  col_index;
  struct double_row_element_t * next_element;
};

typedef struct double_row_element_t double_row_element;

typedef struct  {
  int nrows;
  int ncols;
  int nnz;
  double_row_element** rows;
} double_sparse_matrix;




double_sparse_matrix * initialize_matrix(int nrows, int ncols)
{
  int i;
  double_sparse_matrix* new_matrix;
  new_matrix = (double_sparse_matrix *) malloc(sizeof(double_sparse_matrix));
  new_matrix->rows= (double_row_element **) malloc(sizeof(double_row_element *)*nrows);
  for(i=0;i<nrows;i++)
    {
      (new_matrix->rows)[i]=(double_row_element *) malloc(sizeof(double_row_element));
      (new_matrix->rows)[i]->value=0;
      (new_matrix->rows)[i]->col_index=0;
      (new_matrix->rows)[i]->next_element = 0;
    }
  new_matrix->nrows=nrows;
  new_matrix->ncols=ncols;
  new_matrix->nnz=0;
  return new_matrix;
}


int free_matrix(double_sparse_matrix * matrix)
{
  int i;
  double_row_element* next_element;
  double_row_element* current_element;
  for(i=0;i<matrix->nrows;i++)
    {
      current_element = (matrix->rows)[i];
      while(current_element->next_element!=0)
    {
      next_element=current_element->next_element;
      free(current_element);
      current_element=next_element;
    }
      free(current_element);
    }
  free(matrix->rows);
  free(matrix);
  return 1;
}

int set_value(double_sparse_matrix * matrix,int row, int col, double value)
{

  int i;
  i=0;
  double_row_element* current_element;
  double_row_element* new_element;

  if(row> matrix->nrows || col > matrix->ncols || row <0 || col <0)
    return 1;

  current_element = (matrix->rows)[row];
  while(1)
    {
      if(current_element->col_index==col)
    {
    current_element->value=value;
    return 0;
    }

      else
    if(current_element->next_element!=0)
    {
          if(current_element->next_element->col_index <=col)
        current_element = current_element->next_element;
      else
        if(current_element->next_element->col_index > col)
          {
        new_element = (double_row_element *) malloc(sizeof(double_row_element));
        new_element->value=value;
        new_element->col_index=col;
        new_element->next_element=current_element->next_element;
        current_element->next_element=new_element;
        return 0;
          }
    }
    else
      {
        new_element = (double_row_element *) malloc(sizeof(double_row_element));
        new_element->value=value;
        new_element->col_index=col;
        new_element->next_element=0;
        current_element->next_element=new_element;
        break;
      }

    }

  return 0;
}


double get_value(double_sparse_matrix* matrix,int row, int col)
{
  int i;
  double_row_element * current_element;
  if(row> matrix->nrows || col > matrix->ncols || row <0 || col <0)
    return 0.0;

  current_element = (matrix->rows)[row];
  while(1)
    {
      if(current_element->col_index==col)
    {
      return current_element->value;
    }
      else
    {
      if(current_element->col_index<col && current_element->next_element !=0)
        current_element=current_element->next_element;
      else
        if(current_element->col_index >col || current_element ->next_element==0)
           return 0;
    }
    }

}

将其放入名为linked_list_sparse.c的文件中,然后使用

$ gcc -c linked_list_sparse.c
$ gcc -shared -o linked_list_sparse.so linked_list_sparse.o

接下来考虑下面的python帮助程序代码。

from ctypes import *

class double_row_element(Structure):
    pass

double_row_element._fields_=[("value",c_double),("col_index",c_int),("next_element",POINTER(double_row_element) )]


class double_sparse_matrix(Structure):
    _fields_=[("nrows",c_int),("ncols",c_int),("nnz",c_int),("rows",POINTER(POINTER(double_row_element)))]


double_sparse_pointer=POINTER(double_sparse_matrix)
sparse_library=CDLL("/home/jkantor/linked_list_sparse.so")
initialize_matrix=sparse_library.initialize_matrix
initialize_matrix.restype=double_sparse_pointer
set_value=sparse_library.set_value
get_value=sparse_library.get_value
get_value.restype=c_double
free_matrix=sparse_library.free_matrix

让我们来讨论上面的代码。原始C代码将稀疏矩阵存储为链表。python代码使用ctypes Structure类创建映射C代码中的结构的结构。要创建表示C结构的python对象,只需创建从结构派生的类。这个 _fields_ 类的属性必须设置为字段名和值的元组列表。请注意,如果您需要在结构完全定义之前引用它(如在链表中),您可以先用“Pass”声明它,然后如上所述指定字段内容。还要注意POINTER操作符,它从任何ctypes类型创建一个指针。我们可以直接调用我们的类库如下。

m=double_sparse_pointer()
m=initialize_matrix(c_int(10),c_int(10))
set_value(m,c_int(4),c_int(4),c_double(5.0))
a=get_value(m,c_int(4),c_int(4))
print("%f"%a)
free_matrix(m)

请注意,您可以通过(struct_object).field name访问结构的内容。但是对于指针,有一个contents属性。所以,在上面,m。目录.nrows可以让你进入nrows区域。实际上,您可以按如下方式手动沿着链接列表行走。

m=double_sparse_pointer()
m=initialize_matrix(c_int(10),c_int(10))
set_value(m,c_int(4),c_int(4),c_double(5.0))
a=m.contents.rows[4]
b=a.contents.next_element
b.contents.value
free_matrix(m)