Home > Mobile >  Using eigen objects in C
Using eigen objects in C

Time:11-29

I want to wrap part of Eigen's feature in C, but I am curious how would the automatic storage duration works in such case. For example:

/* eigenwrapper.h */
#ifdef __cplusplus
extern "C" {
#endif


void* create_matrix(int r, int c);
//and other declarations like addition, multiplication, delete ... ....

#ifdef __cplusplus
}
#endif

`

/* eigenwrapper.cxx */
#include <eigen headers>
#include "eigenwrapper.h"

extern "C" {

void* create_matrix(int r, int c) {
    return &MatrixXf(r,c);

}

// and other definitions

}

`

/*main.c*/
#include "eigenwrapper.h"

int main(void) {
    m = create_matrix(3,3);
    /* working with m */
}

I assume that Eigen or C keep tracks of the number of references of the object, but will that work when I return pointer of object to C functions? Will the object being deconstructed when leaving the create_matrix function?

If the automatic storage duration won't work this way, Should I use the new keyword for dynamic allocation? e.g. return new MatrixXf(r,c); Then how could I obtain dynamically allocated, newed, matrices when I have a function returns matA * matB?

CodePudding user response:

As others have noted, C does not keep track of references. If you want a C API, you have to deal with this yourself.

Opaque pointers

As far as wrapping Eigen functions into C API, I would go with opaque pointers instead of void* so that you have at least some type safety.

Here is a suitable header:

#pragma once

#include <stddef.h>
/* using ptrdiff_t */

/** forward-declared opaque handle for matrix */
typedef struct EigenMatrixXf EigenMatrixXf;

#ifdef __cplusplus
extern "C" {
#endif

EigenMatrixXf* eigen_matrixxf_create(ptrdiff_t rows, ptrdiff_t cols);
EigenMatrixXf* eigen_matrixxf_add(
      const EigenMatrixXf* left, const EigenMatrixXf* right);
void eigen_matrixxf_free(EigenMatrixXf* self);

#ifdef __cplusplus
} /* extern "C" */
#endif

And here the cpp file


struct EigenMatrixXf
{
    Eigen::MatrixXf mat;
};
EigenMatrixXf* eigen_matrixxcf_create(ptrdiff_t rows, ptrdiff_t cols)
try {
    return new EigenMatrixXf{ Eigen::MatrixXf(rows, cols) };
} catch(std::bad_alloc&) {
    errno = ENOMEM;
    return nullptr;
}
EigenMatrixXf* eigen_matrixxf_add(
      const EigenMatrixXf* left, const EigenMatrixXf* right)
try {
    return new EigenMatrixXf{ left->mat   right->mat };
} catch(std::bad_alloc&) {
    errno = ENOMEM;
    return nullptr;
}
void eigen_matrixxcf_free(EigenMatrixXf* self)
{ delete self; }

If you want to use fixed-size Eigen objects, read up on the allocator issues here: https://eigen.tuxfamily.org/dox/group__TopicStructHavingEigenMembers.html

Mapping C structs

You can also use Eigen's Map function give an Eigen view to a C struct. https://eigen.tuxfamily.org/dox/group__TutorialMapClass.html There are a few tradeoffs here when it comes to API design and performance (e.g. number of dynamic allocations, alignment, etc.)

Header:

#pragma once

#include <stddef.h>
/* using ptrdiff_t */

typedef struct EigenMatrixXf
{
    float* ptr;
    ptrdiff_t rows, cols;
} EigenMatrixXf;

#ifdef __cplusplus
extern "C" {
#endif

EigenMatrixXf eigen_matrixxf_create(ptrdiff_t rows, ptrdiff_t cols);
EigenMatrixXf eigen_matrixxf_add(
    const EigenMatrixXf* left, const EigenMatrixXf* right);
void eigen_matrixxf_free(EigenMatrixXf* self);

#ifdef __cplusplus
} /* extern "C" */
#endif

Cpp file:


inline Eigen::MatrixXf::MapType map(EigenMatrixXf& ctype)
{ return Eigen::MatrixXf::MapType(ctype.ptr, ctype.rows, ctype.cols); };

inline Eigen::MatrixXf::ConstMapType map(const EigenMatrixXf& ctype)
{ return Eigen::MatrixXf::ConstMapType(ctype.ptr, ctype.rows, ctype.cols); };

EigenMatrixXf eigen_matrixxf_create(ptrdiff_t rows, ptrdiff_t cols)
try {
    return EigenMatrixXf { new float[rows * cols], rows, cols };
} catch(std::bad_alloc&) {
    errno = ENOMEM;
    return EigenMatrixXf { nullptr, 0, 0 };
}
EigenMatrixXf eigen_matrixxf_add(
      const EigenMatrixXf* left, const EigenMatrixXf* right)
{
    EigenMatrixXf rtrn = eigen_matrixxf_create(left->rows, left->cols);
    if(! rtrn.ptr)
      return rtrn;
    map(rtrn) = map(*left)   map(*right);
    return rtrn;
}
void eigen_matrixxf_free(EigenMatrixXf* self)
{ delete[] self->ptr; }
  • Related