How to handle ruby arrays of structs in ruby ffi gem? - c

This is in reference to this question but with structs instead.
I want to use the ruby ffi gem to call a c function which has an array of structs and its length as input variables.
struct MyStruct {
char a;
int b;
float c;
double d;
};
void my_function(struct MyStruct *arr, unsigned int num);
I have created the ruby binding as:
module MyModule
extend FFI::Library
ffi_lib FFI::Library::LIBC
ffi_lib "my_c_lib"
class MyStruct < FFI::Struct
layout(
:a, :char,
:b, :int,
:c, :float,
:d, :double
)
end
attach_function :my_function, [ MyStruct.ptr, :uint ], :void
end
I will like to make a call in ruby code like:
MyModule.my_function([#<MyModule::MyStruct>, #<MyModule::MyStruct>, #<MyModule::MyStruct>], 3)
How do I go about this?
The closest I could get to solving this issue is:
# Make the assumption that `arr` is a ruby array populated with `MyStruct` instances
ptr = FFI::MemoryPointer.new(MyModule::MyStruct, arr.size)
arr.size.times do | i |
ptr.put(MyModule::MyStruct, i, arr[i]) # ERROR in `put': unsupported type 'MyModule::MyStruct' (ArgumentError)
end
MyModule.my_function(ptr, arr.length)
I also replaced the forth line since the put function ask that the first argument be a type where FFI::StructByValue should be returning the type (based on the documentation), but another error appears:
ptr.put(MyModule::MyStruct.by_value, i, arr[i]) # ERROR in `put': unsupported type '#<FFI::StructByValue:0x0123456789abcdef' (ArgumentError)

Related

In C language how to find array size in user defined function with that array being passed from main() [duplicate]

I am trying to write a function that prints out the elements in an array. However when I work with the arrays that are passed, I don't know how to iterate over the array.
void
print_array(int* b)
{
int sizeof_b = sizeof(b) / sizeof(b[0]);
int i;
for (i = 0; i < sizeof_b; i++)
{
printf("%d", b[i]);
}
}
What is the best way to do iterate over the passed array?
You need to also pass the size of the array to the function.
When you pass in the array to your function, you are really passing in the address of the first element in that array. So the pointer is only pointing to the first element once inside your function.
Since memory in the array is continuous though, you can still use pointer arithmetic such as (b+1) to point to the second element or equivalently b[1]
void print_array(int* b, int num_elements)
{
for (int i = 0; i < num_elements; i++)
{
printf("%d", b[i]);
}
}
This trick only works with arrays not pointers:
sizeof(b) / sizeof(b[0])
... and arrays are not the same as pointers.
Why don't you use function templates for this (C++)?
template<class T, int N> void f(T (&r)[N]){
}
int main(){
int buf[10];
f(buf);
}
EDIT 2:
The qn now appears to have C tag and the C++ tag is removed.
For C, you have to pass the length (number of elements)of the array.
For C++, you can pass the length, BUT, if you have access to C++0x, BETTER is to use std::array. See here and here. It carries the length, and provides check for out-of-bound if you access elements using the at() member function.
In C99, you can require that an array an array has at least n elements thusly:
void print_array(int b[static n]);
6.7.5.3.7: A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many
elements as specified by the size expression.
In GCC you can pass the size of an array implicitly like this:
void print_array(int n, int b[n]);
You could try this...
#include <cstdio>
void
print_array(int b[], size_t N)
{
for (int i = 0; i < N; ++i)
printf("%d ", b[i]);
printf("\n");
}
template <size_t N>
inline void
print_array(int (&b)[N])
{
// could have loop here, but inline forwarding to
// single function eliminates code bloat...
print_array(b, N);
}
int main()
{
int a[] = { 1, 2 };
int b[] = { };
int c[] = { 1, 2, 3, 4, 5 };
print_array(a);
// print_array(b);
print_array(c);
}
...interestingly b doesn't work...
array_size.cc: In function `int main()':
array_size.cc:19: error: no matching function for call to `print_array(int[0u])'
JoshD points out in comments below the issue re 0 sized arrays (a GCC extension), and the size inference above.
In c++ you can also use a some type of list class implemented as an array with a size method or as a struct with a size member(in c or c++).
Use variable to pass the size of array.
int sizeof_b = sizeof(b) / sizeof(b[0]); does nothing but getting the pre-declared array size, which is known, and you could have passed it as an argument; for instance, void print_array(int*b, int size). size could be the user-defined size too.
int sizeof_b = sizeof(b) / sizeof(b[0]); will cause redundant iteration when the number of elements is less than the pre-declared array-size.
The question has already some good answers, for example the second one. However there is a lack of explanation so I would like to extend the sample and explain it:
Using template and template parameters and in this case None-Type Template parameters makes it possible to get the size of a fixed array with any type.
Assume you have such a function template:
template<typename T, int S>
int getSizeOfArray(T (&arr)[S]) {
return S;
}
The template is clearly for any type(here T) and a fixed integer(S).
The function as you see takes a reference to an array of S objects of type T, as you know in C++ you cannot pass arrays to functions by value but by reference so the function has to take a reference.
Now if u use it like this:
int i_arr[] = { 3, 8, 90, -1 };
std::cout << "number f elements in Array: " << getSizeOfArray(i_arr) << std::endl;
The compiler will implicitly instantiate the template function and detect the arguments, so the S here is 4 which is returned and printed to output.

Pass data from a C function via double pointer in Cython

I want to use a small C routine with Cython. The C function itself is
#include <stdio.h>
#include "examples.h"
void add_array(int **io_array, int n) {
int i;
int *array;
array = (int *) malloc(n * sizeof(int));
for(i = 0; i < n; i++) {
array[i] = i;
}
*io_array = array;
}
And the function prototype:
#ifndef EXAMPLES_H
#define EXAMPLES_H
void add_array(int **io_array, int n);
#endif
Now I want to use Cython to interface the C function with:
cdef extern from "examples.h":
void add_array(int **io_array, int n)
import numpy as np
def add(arr):
if not arr.flags['C_CONTIGUOUS']:
arr = np.ascontiguousarray(arr, dtype=np.int32)
cdef int[::1] arr_memview = arr
add_array(&arr_memview[0], arr_memview.shape[0])
return arr
When compiling it gives the error:
pyexamples.pyx:13:14: Cannot assign type 'int *' to 'int **'
What is the right way to interface this function?
It will not work out-of-the-box with numpy-arrays. You will have to make the memory management yourself, for example:
%%cython
from libc.stdlib cimport free
def doit():
cdef int *ptr;
add_array(&ptr, 5)
print(ptr[4])
free(ptr) #memory management
The difference to your attempt: &arr_memview[0] is pointer to an integer array, but what you need for your function is a pointer to a pointer to an integer array - that is what &ptr is.
The problem with your function is, that it has too many responsibilities:
it allocates the memory
it initializes the memory
It would be easier, if add_array would only be doing the second part, i.e.
void add_array(int *io_array, int n) {
int i;
for(i = 0; i < n; i++) {
io_array[i] = i;
}
}
And thus any memory could be initialized (also memory which was not allocated with malloc).
However, it is possible to create a numpy-array using the returned pointer ptr, it is just less straight forward:
cimport numpy as np
import numpy as np
np.import_array() # needed to initialize numpy-data structures
cdef extern from "numpy/arrayobject.h":
void PyArray_ENABLEFLAGS(np.ndarray arr, int flags) #not include in the Cython default include
def doit():
cdef int *ptr;
add_array(&ptr, 5)
# create numpy-array from data:
cdef np.npy_intp dim = 5
cdef np.ndarray[np.int32_t, ndim=1] arr = np.PyArray_SimpleNewFromData(1, &dim, np.NPY_INT32, ptr)
# transfer ownership of the data to the numpy array:
PyArray_ENABLEFLAGS(arr, np.NPY_OWNDATA)
return arr
The following is worth mentioning:
np.import_array() is needed to be able to use all of the numpy's functionality. Here is an example of what can happen, if np.import_array() isn't called.
After PyArray_SimpleNewFromData, the data itself isn't owned by the resulting numpy array, thus we need to enable the OWNDATA-flag, otherwise there will be a memory leak.
It is not obvious, that the resulting numpy-array can be responsible for freeing the data. For example instead of using malloc/free it could be using Python's memory allocator.
I would like to elaborate about point 3. above. Numpy uses a special function to allocate/deallocate memory for data - it is PyDataMem_FREE and uses system's free for it. So in your case (using system's malloc/free in add_array) everything is Ok. (PyDataMem_FREE should not be confused with PyArray_free, as I did in an earlier version of the answer. PyArray_free is responsible for freeing other elements (array itself, and dimension/strides data, not data-memory) of the numpy-array, see here and is different depending on Python version).
A more flexible/safe approach is to use PyArray_SetBaseObject as shown in this SO-post.

cython - initialize 2d c-array

I would like to create a 2D-array within a cdef function with the number of elements in each dimension depending on parameters passed to the function. E.g.:
cdef int[:,:] c_volumecheck(int n):
cdef:
const int comb = 2**n
const int nt = n
int match[comb][nt]
size_t i,j
# initialize values
for i in range(comb):
for j in range(n):
match[i][j] = 0
return match
However, assigning to comb and nt a constant expression does not seem to work as I get the error "Not allowed in a constant expression" in line int match[comb][nt]. Manually providing the respective values work (match[8][3] for e.g. n=3). That is not an option however, as these values change during the program.
The second thing is, that I do not seem to understand how to return this array to another cdef or def function in the same .pyx-script: int[:,:] does not seem to correspond to a 2d-array like the one I want to initialize.

How to initialize array of pointers to functions?

I have following code:
typedef int (*t_Function) (int x);
t_Function Functions[MAX_FUNCTIONS];
int f(int x)
{
return 0;
}
But I cannot initialize it properly. If I add following line:
Functions[0] = f;
then compiler generates following error:
prog.c:217: warning: data definition has no type or storage class
prog.c:217: error: conflicting types for Functions
How to initialize this array of pointers to functions?
You should either do it inside a function, where Functions[0] = f; works fine, or with an array initializer:
t_Function Functions[MAX_FUNCTIONS] = {f};
For this to work, f (and all functions you want in Functions) must have been declared at the point where this definition appears. Note that all other MAX_FUNCTIONS-1 elements of Functions will be NULL automatically if at least one of them is filled this way.

How do you get the size of array that is passed into the function?

I am trying to write a function that prints out the elements in an array. However when I work with the arrays that are passed, I don't know how to iterate over the array.
void
print_array(int* b)
{
int sizeof_b = sizeof(b) / sizeof(b[0]);
int i;
for (i = 0; i < sizeof_b; i++)
{
printf("%d", b[i]);
}
}
What is the best way to do iterate over the passed array?
You need to also pass the size of the array to the function.
When you pass in the array to your function, you are really passing in the address of the first element in that array. So the pointer is only pointing to the first element once inside your function.
Since memory in the array is continuous though, you can still use pointer arithmetic such as (b+1) to point to the second element or equivalently b[1]
void print_array(int* b, int num_elements)
{
for (int i = 0; i < num_elements; i++)
{
printf("%d", b[i]);
}
}
This trick only works with arrays not pointers:
sizeof(b) / sizeof(b[0])
... and arrays are not the same as pointers.
Why don't you use function templates for this (C++)?
template<class T, int N> void f(T (&r)[N]){
}
int main(){
int buf[10];
f(buf);
}
EDIT 2:
The qn now appears to have C tag and the C++ tag is removed.
For C, you have to pass the length (number of elements)of the array.
For C++, you can pass the length, BUT, if you have access to C++0x, BETTER is to use std::array. See here and here. It carries the length, and provides check for out-of-bound if you access elements using the at() member function.
In C99, you can require that an array an array has at least n elements thusly:
void print_array(int b[static n]);
6.7.5.3.7: A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many
elements as specified by the size expression.
In GCC you can pass the size of an array implicitly like this:
void print_array(int n, int b[n]);
You could try this...
#include <cstdio>
void
print_array(int b[], size_t N)
{
for (int i = 0; i < N; ++i)
printf("%d ", b[i]);
printf("\n");
}
template <size_t N>
inline void
print_array(int (&b)[N])
{
// could have loop here, but inline forwarding to
// single function eliminates code bloat...
print_array(b, N);
}
int main()
{
int a[] = { 1, 2 };
int b[] = { };
int c[] = { 1, 2, 3, 4, 5 };
print_array(a);
// print_array(b);
print_array(c);
}
...interestingly b doesn't work...
array_size.cc: In function `int main()':
array_size.cc:19: error: no matching function for call to `print_array(int[0u])'
JoshD points out in comments below the issue re 0 sized arrays (a GCC extension), and the size inference above.
In c++ you can also use a some type of list class implemented as an array with a size method or as a struct with a size member(in c or c++).
Use variable to pass the size of array.
int sizeof_b = sizeof(b) / sizeof(b[0]); does nothing but getting the pre-declared array size, which is known, and you could have passed it as an argument; for instance, void print_array(int*b, int size). size could be the user-defined size too.
int sizeof_b = sizeof(b) / sizeof(b[0]); will cause redundant iteration when the number of elements is less than the pre-declared array-size.
The question has already some good answers, for example the second one. However there is a lack of explanation so I would like to extend the sample and explain it:
Using template and template parameters and in this case None-Type Template parameters makes it possible to get the size of a fixed array with any type.
Assume you have such a function template:
template<typename T, int S>
int getSizeOfArray(T (&arr)[S]) {
return S;
}
The template is clearly for any type(here T) and a fixed integer(S).
The function as you see takes a reference to an array of S objects of type T, as you know in C++ you cannot pass arrays to functions by value but by reference so the function has to take a reference.
Now if u use it like this:
int i_arr[] = { 3, 8, 90, -1 };
std::cout << "number f elements in Array: " << getSizeOfArray(i_arr) << std::endl;
The compiler will implicitly instantiate the template function and detect the arguments, so the S here is 4 which is returned and printed to output.

Resources