Page 1 of 1

Arg!!! - C Interfacing Problem

Posted: Thu Jun 18, 2009 6:11 pm
by Harnon
I haven't had much experience with c, but I've had to dwell into it in order to figure out what i am doing wrong with my c binding.
I finally distilled it to this code -
Test C code (test.c)

typedef float testing[2];
void tester (testing* in, float a1, float a2, float a3, float a4)
{
in[0][0] = a1;
in[0][1] = a2;
in[1][0] = a3;
in[1][1] = a4;
}

What i want is to create a testing* in lisp, fill it using the function tester, and print the results back in lisp by accessing the testing* pointer. The code!:

Code: Select all

(defcfun "tester" :void (pt :pointer)
  (a1 :float) (a2 :float) (a3 :float) (a4 :float))
(cffi:with-foreign-object (a :pointer 2)
  (tester a 1.0 2.0 44.0 2.00)
  (print  (mem-aref (mem-aref a :pointer) :float))
)
I also tried this:

Code: Select all

(with-foreign-object (a :pointer 2)
  (setf (mem-aref a :pointer) (cffi:foreign-alloc :float :initial-contents '(0.0 0.0)))
  (setf (mem-aref a :pointer) (cffi:foreign-alloc :float :initial-contents '(0.0 1.0)))
  (tester a 1.0 2.0 44.0 2.00)
  (print  (mem-aref (mem-aref a :pointer) :float))
)
Each time, allegro throws an error, saying something like

Error: Attempt to take the car of #<Function MEMREF-INT> which is not listp.
[condition type: TYPE-ERROR]

I have NO clue whats wrong :oops:

Please Help!!!! :o

Re: Arg!!! - C Interfacing Problem

Posted: Fri Jun 19, 2009 12:39 am
by ramarren
Some Googling shows that typedef'ing arrays is not always a good idea, since it makes C treat it strangely. As far as I can tell it makes in=(*in). Changing the C file to:

Code: Select all

void tester2 (float** in, float a1, float a2, float a3, float a4)
{
  in[0][0] = a1;
  in[0][1] = a2;
  in[1][0] = a3;
  in[1][1] = a4;
}
and Lisp code to:

Code: Select all

(cffi:defcfun "tester2" :void (pt :pointer)
              (a1 :float) (a2 :float) (a3 :float) (a4 :float))
(defun test ()
  (cffi:with-foreign-objects ((a :pointer 2)
                              (a1 :float 2)
                              (a2 :float 2))
    (setf (cffi:mem-aref a :pointer 0) a1
          (cffi:mem-aref a :pointer 1) a2)
    (tester2 a 1.0 2.0 44.0 2.00)
    (print (vector (cffi:mem-aref (cffi:mem-aref a :pointer 0) :float 0)
                   (cffi:mem-aref (cffi:mem-aref a :pointer 0) :float 1)
                   (cffi:mem-aref (cffi:mem-aref a :pointer 1) :float 0)
                   (cffi:mem-aref (cffi:mem-aref a :pointer 1) :float 1)))))
works.

With original C version the two float arrays seems to be flattened into a single vector, and just:

Code: Select all

(defun test ()
  (cffi:with-foreign-object (a :float 4)
    (tester a 1.0 2.0 44.0 2.00)
    (print (vector (cffi:mem-aref a :float 0)
                   (cffi:mem-aref a :float 1)
                   (cffi:mem-aref a :float 2)
                   (cffi:mem-aref a :float 3)))))
works. I suppose this is somewhat logical, as when you substitute typedef in C you get:

Code: Select all

testing* => (float[2])(*) => float[2][]
which is a two-dimensional array, which is a vector in a way.

Re: Arg!!! - C Interfacing Problem

Posted: Fri Jun 19, 2009 7:41 pm
by Harnon
Thx! That worked perfectly. :mrgreen: