All Manuals > LispWorks Foreign Language Interface User Guide and Reference Manual > 4 Advanced Uses of the FLI > 4.2 Modifying, passing and returning strings


4.2.5 Calling a C function that takes an array of strings

Suppose you have a C function declared like this:

extern "C" void foo( const char** StringArray);

To call this from Lisp you need to first allocate the foreign memory for each piece of data, that is the array itself and each string. Assuming that foo does not capture any of the pointers, you can give this memory dynamic extent as follows:

(defun convert-to-dynamic-foreign-array (strings)
  (let* ((count (length strings))
           :nelems (1+ count) ; assume NULL terminated
           :type '(:pointer :char))))
    (dotimes (index count)
      (setf (fli:dereference array :index index)
             (elt strings index))))
    (setf (fli:dereference array :index count) nil)
(fli:define-foreign-function (%foo foo)
    ((string-array (:pointer (:pointer :char)))))
(defun foo (strings)
  (fli:with-dynamic-foreign-objects ()  ; provide a dynamic scope
    (%foo (convert-to-dynamic-foreign-array strings))))

Here is a similar example converting Lisp strings to **char or *char[] which by default allocates using malloc (the value :static for the allocation argument):

(defun convert-strings-to-foreign-array (strings &key 
                                                 (allocation :static))
  (let* ((count (length strings))
         (array (fli:allocate-foreign-object 
                 :type '(:pointer (:unsigned :char))
                 :nelems (1+ count)
                 :initial-element nil
                 :allocation allocation)))
    (loop for index from 0
          for string in strings
          do (setf (fli:dereference array :index index)
                    :external-format :utf-8
                    :allocation allocation)))

If you call it frequently, then you will probably want to free the array (and the strings inside it). Alternatively, you can give the array and its strings dynamic scope if the foreign side does not keep a pointer to the data, like this:

(fli:with-dynamic-foreign-objects ()
  (let ((array (convert-strings-to-foreign-array 
                strings :allocation :dynamic)))
    (%foo array)))

LispWorks Foreign Language Interface User Guide and Reference Manual - 7 Dec 2011