Notes
This macro allows for the precise way to assemble a complex number from its real and imaginary components, e.g. with (double complex)((double)x + _Imaginary_I * (double)y). This pattern was standardized in C11 as the macro CMPLX.
Походу лишперы таки не умеют элементарно читать доки.
6.2.5 Types
13 Each complex type has the same representation and alignment requirements as an array type containing exactly two elements of the corresponding real type; the first element is equal to the real part, and the second element to the imaginary part, of the complex number.
Ладно, братан. Не обижайся на «лишпера». Я понимаю, что ты привык к тепличным условиям виртуальной машины лиспа где тебе не нужно прибирать за собой и отличать тип от представления типа в памяти. И что не привык читать документацию, потому что для лиспа её либо вообще не было, либо ссылки давно сдохли.
Так что я помогу тебе. SysV ABI для x86_64 говорит нам
Arguments of complex T where T is one of the types float or double
are treated as if they are implemented as:
struct complexT {
T real;
T imag;
};
Для i386 я подобного явного не нашёл, но, походу, там так же.
Допустим, получил я :pointer на что-то. Хочу в creal это передать. Что мне делать? Оно принимает отнюдь не :pointer, как уже мог убедиться наш незадачливый лиспер.
13 Each complex type has the same representation and alignment requirements as an array type containing exactly two elements of the corresponding real type; the first element is equal to the real part, and the second element to the imaginary part, of the complex number.
Это, как я понял, из текста стандарта C99. Т.е. если описать организацию данных в лиспе то вроде должно получиться надёжно и кроссплатформенно. Мне в целях изучения это более интересно. Но вот не могу понять cffi:define-foreign-type и как с ним всё это грамотно описать.
если описать организацию данных в лиспе то вроде должно получиться надёжно и кроссплатформенно
Да не получится кроссплатформенно, что ж до тебя всё не допрёт. representation никак не связано с тем, как оно передаётся в функцию. double[2] и struct { double; double; }; имеют на x86_64 одно и то же представление, только вот первое передаётся как указатель, а второе — в регистрах xmm0 и xmm1.
There is no applicable method for the generic function
#<STANDARD-GENERIC-FUNCTION CFFI:TRANSLATE-INTO-FOREIGN-MEMORY (6)>
when called with arguments
(#.(SB-SYS:INT-SAP #XB13B9FEC)
#<C-COMPLEX-DOUBLE-TCLASS C-COMPLEX-DOUBLE>
#.(SB-SYS:INT-SAP #XB13B9FD0)).
[Condition of type SIMPLE-ERROR]
Нужно ли в этом коде подчищать данные которые возвращает (conj z)?
Нет. В этом и смысл возврата по значению. libffi создаёт временную структуру, на которую применяется translate-from-foreign, а затем структура удаляется.
И всё же я не понимаю - а если я хочу сначала оттранслировать данные в родной вид и потом натравить на эти же данные cffi-функцию? Тогда после translate-from-foreign меня ждёт облом?
И всё же я не понимаю - а если я хочу сначала оттранслировать данные в родной вид и потом натравить на эти же данные cffi-функцию? Тогда после translate-from-foreign меня ждёт облом?
Что значит «на эти же данные»? translate-from-foreign тебе вернёт лисповый complex. При отправке его в cffi-функцию создастся новый временный struct, который будет заполнен при помощи translate-into-foreign-memory и будет существовать пока работает эта функция.
P.S. С учётом того, что все вызовы «по значению», временные объекты будут созданы через libffi на стеке, а не через malloc/free. То есть явного освобождения памяти нет.
translate-from-foreign тоже трассируется, но оптимизация макрораскрытием работает
Судя по исходнику, этот кусок у них временно поломан:
(define-compiler-macro mem-set
(&whole form value ptr type &optional (offset 0))
"Compiler macro to open-code (SETF MEM-REF) when type is constant."
(if (constantp type)
(let* ((parsed-type (parse-type (eval type)))
(ctype (canonicalize parsed-type)))
;; Bail out when using emulated long long types.
#+cffi-sys::no-long-long
(when (member ctype '(:long-long :unsigned-long-long))
(return-from mem-set form))
(if (aggregatep parsed-type) ; XXX: skip for now.
form ; use expand-into-foreign-memory when available.
`(%mem-set ,(expand-to-foreign value parsed-type)
,ptr ,ctype ,offset)))
form))
Я второй командой определил функцию так чтобы она принимала указатель и следующей командой вызываю её с передачей указателя, но возвращается какая-то хрень. Может в git-версии опять что-то поломали?
Или твой код здесь на моей платформе работать не должен?
Не должен. Он вообще нигде работать не должен. Работает только потому, что я писал (cimag (make-double-complex 1.0d0 2.0d0)) и временные данные не успевали потеряться. Если писать (setf a (make-double-complex 1.0d0 2.0d0)) (cimag a), то уже не работает.
Please note that this interface is only for those that must know about
the values contained in a relevant struct. If the library you are
interfacing returns an opaque pointer that needs only be passed to
other C library functions, by all means just use :pointer or a
type-safe definition munged together with defctype and type
translation. To pass or return a structure by value to a function,
load the cffi-libffi system and specify the structure as (:struct
structure-name). To pass or return the pointer, you can use
either :pointer or (:pointer (:struct structure-name)).
Допустим такая ситуация - в библиотеке, которую мне надо использовать
через cffi, типа ООП и инкапсуляция - структуры в доках не описаны и они
могут от версии к версии меняться, но в доках хорошо описан интерфейс
работы с этими структурами, который если и будет меняться то
незначительно и которого вполне достаточно для использования библиотеки. Я хочу попробовать
работать со структурами не описывая их передавая функциям интерфейса
указатели. Я правильно понимаю что можно не писать на C обёртки
функций чтобы те работали с указателями?
Вот есть в библиотеке fftw такой тип как fftw_plan и похоже это
банально указатель на структуру. Это такая договорённость писать библиотеки или
мне просто повезло?
Я хочу попробовать работать со структурами не описывая их передавая функциям интерфейса указатели. Я правильно понимаю что можно не писать на C обёртки функций чтобы те работали с указателями?
В смысле, не описывая поля структуры? Или что за «обёртки»?
Если работа через указатель, то структуру можно не описывать (если тебе не надо читать/писать её поля самому).
Вот есть в библиотеке fftw такой тип как fftw_plan и похоже это банально указатель на структуру. Это такая договорённость писать библиотеки или мне просто повезло?
Договоренность. Если передавать структуру, а не указатель на неё, то при вызове функции будут копироваться все поля структуры. Если структура достаточно большая, то это неудобно.