LINUX.ORG.RU

[wrapper] Переменное число аргументов

 


0

1

Как при написании оберток к библиотекам пишут обертки к фукнциям переменного числа аргументов, например printf? Конкретно — на лиспе есть функция, которая должна быть оберткой того же printf, при этом в рантайме доступ к аргументам производится последовательным car'ом. Как сформировать итоговый printf или же как сформировать va_list при наличии соответствующей функции типа vprintf?

Интересует, естественно, не сам printf, а printw из curses.

P.S. когда-то уже сталкивался с этой проблемой, но насколько помню не решил ее, а переписал нужную функцию на целевом языке.

★★★★★

printf/printw - там же просто сообщение формируется с помощью интерполяции разных %i, %s и т.п., его можно сформировать с лисповой стороны с помощью format и отдать уже готовое в printf/printw (т.е. не использовать аргументы из эллипсиса).

Либо как-то так:

;; FIXME: defun?
(defmacro printf (format &rest args+types)
  `(cffi:foreign-funcall "printf" :string ,format ,@args+types :int))

тут cffi:foreign-funcall развернётся в примитив реализации, который будет просто класть свои аргументы в стек по очереди.

Либо настраивать полноценный маршалинг (http://www.cliki.net/virgil).

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

;; FIXME: defun?

В CFFI:

;;; If we find a &REST token at the end of ARGS, it means this is a
;;; varargs foreign function therefore we define a lisp macro using
;;; %DEFCFUN-VARARGS. Otherwise, a lisp function is defined with
;;; %DEFCFUN.

т.е. если в определении есть &REST, то CFFI для DEFCFUN генерирует не функцию, а макрос:

(defcfun "printf" :int
  (format :string)
  &rest)

; (printf "%c %d %.2f %s" :char 34 :short 35 :float pi :string "foo")
; ;-> 13

; (macro-function 'printf)
; ;-> #<FUNCTION (MACRO-FUNCTION PRINTF) {BC169ED}>

чисто гипотетически, это могла бы быть функция (можно попробовать хакнуть это для SBCL), и (чисто теоретически) она могла бы сама выводить foreign типы.

quasimoto ★★★★
()
Ответ на: комментарий от buddhist

И биндинг пишется на сишной стороне для встраиваемого интерпретатора.

Для этого нужен либо компилятор (как в CL - такие вещи делаются макросами, можно считать это разновидностью компиляции), либо интерпретатор с JIT. Если JIT прикручивается, то можно написать примерно так:


int
myPrintf(char *fmt, cons *args)
{
    lispobj *x  = car(args);
    lispobj *xs = cdr(args);
    while (1) {
        switch (typeOf(x)) {
            /* Тут генерируется код для JIT. */
        }
        if (xs == NULL)
            break;
        else
            switch (typeOf(xs)) {
                case CONS:
                    x  = car(xs);
                    xs = cdr(xs);
                    break;
                default:
                    /* Тут ещё rest от dotted list,
                       тоже нужно генерировать код для JIT. */
            }
    }

    /* Тут JIT код компилируется и мы звоним на printf(3),
       за соглашением о вызове на данной $ARCH следит JIT компилятор. */

}
quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Ну и ещё можно обходить этот связный список и вручную готовит стек (инлайном asm-а) и потом переходить на точку входа (тоже asm-ом). Но так получится непереносимо.

quasimoto ★★★★
()

Спасибо за ответы!

buddhist ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.