доступ к 2D-массиву внутри структуры из C в python с помощью ctypes - PullRequest
3 голосов
/ 26 мая 2020

C код: использует фрактал_креат () для присвоения двумерного массива массиву значений в структуре фрактал_т

//2D.c

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

typedef struct 
{
    size_t height;
    size_t width;
    double values[];
} fractal_t;

void fractal_destroy (fractal_t* f)
{
    free(f);
}

void fractal_fill (fractal_t* f)
{
    double (*array_2D)[f->width] = (double(*)[f->width]) f->values;

    for (size_t height=0; height < f->height; height++)
    {
        for (size_t width=0; width < f->width; width++)
        {
            array_2D[height][width] = width; // whatever value that makes sense
        }
    }
}

void fractal_print (const fractal_t* f)
{
    double (*array_2D)[f->width] = (double(*)[f->width]) f->values;

    for(size_t height=0; height < f->height; height++)
    {
        for(size_t width=0; width < f->width; width++)
        {
            printf("%.5f ", array_2D[height][width]); 
        }
        printf("\n");
    }
}

fractal_t* fractal_create (size_t height, size_t width)
{
    // using calloc since it conveniently fills everything with zeroes
    fractal_t* f = calloc(1, sizeof *f + sizeof(double[height][width]) );
    f->height = height;
    f->width = width;
    // ...
    fractal_fill(f); // fill with some garbage value
    fractal_print(f);
    return f;
}

int main (void)
{
    int h = 3;
    int w = 4;

    fractal_t* fractal = fractal_create(h, w);
    fractal_destroy(fractal);
}

Я пытаюсь получить доступ к этому двумерному массиву значений из python с использованием ctypes

python код:

from ctypes import *

h = 3
w = 4

class fractal_t(Structure):
    _fields_ = [("a", c_int),
                ("values", (c_double * h) * w)]

slib = cdll.LoadLibrary('/2D.so')
t = fractal_t
fun = slib.fractal_create
t  = fun(c_int(h), 
    c_int(w))

p1 = fractal_t.from_address(t)

print(p1.values[0][0])
print(p1.values[0][1])
print(p1.values[0][2])

for i in p1.values: 
    print(i, end=" \n")
    for j in i:
        print(j, end=" \n")

вывод:

0.00000 1.00000 2.00000 3.00000 
0.00000 1.00000 2.00000 3.00000 
0.00000 1.00000 2.00000 3.00000 
2e-323
0.0
1.0
<__main__.c_double_Array_3 object at 0x7f5c7836f8c8> 
2e-323 
0.0 
1.0 
<__main__.c_double_Array_3 object at 0x7f5c7836fb70> 
2.0 
3.0 
0.0 
<__main__.c_double_Array_3 object at 0x7f5c7836f8c8> 
1.0 
2.0 
3.0 
<__main__.c_double_Array_3 object at 0x7f5c7836fb70> 
0.0 
1.0 
2.0 

Первые 3 строки вывода печатаются из фрактальной_принт () в C. Когда я попытался получить доступ к 2D-массиву с помощью p1.values ​​[0] [0], я не получил правильного значения. Не уверен, что здесь не так.

1 Ответ

1 голос
/ 27 мая 2020

Я решил это

Python код:

import numpy
from ctypes import *

col = 2
row = 3

lib = cdll.LoadLibrary('./2d_array.so')

class Array_2d(Structure):
    _fields_ = [('col', c_int), 
                ('row', c_int),
                ("data", (c_double * row) * col)]


fun = lib.initialize_Array_2d
point_ptr = fun(c_int(col), c_int(row))

fun = lib.cfun
fun(c_void_p(point_ptr))

p1 = Array_2d.from_address(point_ptr)

print("from python")

print(p1.data[0][0], p1.data[0][1],p1.data[0][2])
print(p1.data[1][0], p1.data[1][1],p1.data[1][2])

fun = lib.free_Array_2d
point_ptr = fun()

C код:

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

typedef struct {
    int col;
    int row;
    double data[];
} Array_2d;

Array_2d* f;

Array_2d* initialize_Array_2d(int col, int row)
{
    f = calloc(1, sizeof *f + sizeof(double[col][row]));
    f->col = col;
    f->row = row;
    return f;
}

void free_Array_2d()
{
    free(f);
}

void cfun(void * stv) 
{
    Array_2d * f = (Array_2d *) stv;

    double (*array_2D)[f->row] = (double(*)[f->row]) f->data;

    for (size_t i=0; i < f->col; i++)
    {
        for (size_t j=0; j < f->row; j++)
        {
            array_2D[i][j] = rand() % 10 + 1; // some random values
        }
    }

    printf("from C : \n");
    for(size_t i=0; i < f->col; i++)
    {
        for(size_t j=0; j < f->row; j++)
        {
            printf("%.1f ", array_2D[i][j]); 
        }
        printf("\n");
    }
    printf("\n");
}

Вывод:

from C : 
4.0 7.0 8.0 
6.0 4.0 6.0 

from python
4.0 7.0 8.0
6.0 4.0 6.0
...