valavapi

How to use a fixed size C array type in vala?


Assume I have a C code (dcomplex.h):

typedef double dcomplex[2];

and want to use such a data type in vala. What can be the minimal vapi file and vala call for it?

(The ultimate goal is to use the C99 complex.h types.)

I tried many variants of the following dcomplex.vapi file:

[CCode (cheader_filename = "dcomplex.h")]
namespace DComplex {
   [SimpleType]
   [CCode (cname = "dcomplex", has_type_id = false)]
   public struct DoubleComplex {
   }
}

and using in vala code like:

using DComplex;
void main()
{  
   DoubleComplex x = {1.0, 2.0};
   stdout.printf("x = %f + i %f\n", x[0], x[1]);
}

The compilation

valac --vapidir . --pkg dcomplex test.vala

leads to errors:

error: too many expressions in initializer list for `Complex.DoubleComplex'
DoubleComplex x = {1.0, 2.0};
                   ^^^

error: The expression `Complex.DoubleComplex' does not denote an array
stdout.printf("x = %f + i %f\n", x[0], x[1]);
                                 ^^^^

Solution

    1. public struct DoubleComplex: I don't think you can bind to a typedefed C array and expect Vala to be able to access its members or fields.

    2. DoubleComplex x = {1.0, 2.0}; is a initialization of arrays. You will not be able to use this initialization since we cannot let Vala knows its type is an binded "opaque" array.

    I understand you want to use C99 complex features, so, bellow, I present my solution to bind to complex.h. To make the complex header more Vala fiendly, I'd not write and VAPI to bind it directly, instead I'd write a C wrapper object based style typedefing double complex to something Vala can bind to.

    First I'll show the wrapper, it is composed of three files:

    file Complex.h

    #include <complex.h>
    
    typedef double complex dcomplex;
    
    void dcomplex_make (dcomplex * c, double r, double i);
    
    double dcomplex_real (dcomplex * c);
    double dcomplex_imag (dcomplex * c);
    

    file Complex.c

    #include "Complex.h"
    
    void dcomplex_make (dcomplex * c, double r, double i)
    {
        *c = CMPLX(r, i);
    }
    
    double dcomplex_real (dcomplex * c)
    {
        return creal(*c);
    }
    
    double dcomplex_imag (dcomplex * c)
    {
        return cimag(*c);
    }
    

    file Complex.vapi

    [CCode (cheader_filename = "Complex.h")]
    namespace Complex
    {
        [CCode (cname = "dcomplex")]
        public struct DComplex {
            [CCode (cname = "dcomplex_make")]
            public DComplex (double real, double imaginary);
    
            [CCode (cname = "dcomplex_real")]
            public double real ();
    
            [CCode (cname = "dcomplex_imag")]
            public double imag ();
        }
    }
    

    Now that you have the wrapper and VAPI, you can use it in Vala code:

    file Main.vala

    using Complex;
    
    class Main {
        static void main() {
            DComplex c = DComplex(10, 20);
    
            stdout.printf("C Complex Type = %f %f\n", c.real(), c.imag());
        }
    }
    

    To build and run:

    # valac Main.vala Complex.vapi Complex.c
    # ./Main
    

    The presented example outputs:

    C Complex Type = 10.000000 20.000000