Вопросы по использованию FFI

Столкнулись с проблемой в использовании макросов? Здесь можно получить помощь.
User avatar
John Doe
Бюрократ
Posts: 12530
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 33 times
Been thanked: 234 times

Вопросы по использованию FFI

Post by John Doe » Tue 21 May, 2013 20:20

FFI — одна из стандартных библиотек luajit.
Позволяет из Lua кода вызывать внешние C-функции и использовать структуры данных C.
В данной теме задаём вопросы по использованию FFI

Примеры готовых скриптов:

Предупреждение: viewtopic.php?p=147610#p147610

EGez
Posts: 144
Joined: Thu 04 Oct, 2012 13:53
Location: Hamburg, DE
Has thanked: 2 times
Been thanked: 2 times

Re: ffi.C и unicode/multibyte ... string

Post by EGez » Tue 17 Dec, 2013 18:03

Latest post of the previous page:

HaRT wrote:Машина машине рознь. На многих RISC-архитектурах у char* и short* почти наверняка будет разное выравнивание, что чревато в лучшем случае просадкой производительности, а в типичном — “unaligned” exception. И да, некоторые из таких машин работают (работали?) под управлением тех или иных Windows.
Ну, совсем экзотикой можно принебречь...

User avatar
John Doe
Бюрократ
Posts: 12530
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 33 times
Been thanked: 234 times

Re: Вопросы по использованию FFI

Post by John Doe » Mon 24 Feb, 2014 15:41

Хотел составить функцию для превращения строки Lua в указатель, для передачи входных параметров в разные WinAPI-функции.
Сделал, работает:

Code: Select all

local function str2p(str)
  return ffi.cast("void*",win.Utf8ToUtf16(str .. '\0'))
end
Но перечитав тему засомневался, ведь результат win.Utf8ToUtf16 при выходе из функции становится мусором?
С другой стороны, полученный указатель и не требуется долго хранить...

В общем, на первой странице похожий пример рассматривался, решили что нельзя.
Если только не сохранить результат win.Utf8ToUtf16 в актуальную переменную. Или использовать ffi.new/ffi.copy

Хотя тогда я несовсем понимаю, почему в другом примере на первой странице делается так:

Code: Select all

local PluginId = ffi.cast("const GUID*", win.Uuid("4EBBEFC8-2084-4B7F-94C0-692CE136894D"))
local MenuId = ffi.cast("const GUID*", win.Uuid("6C47D27E-3E7E-4C65-916D-E1B1A31527AD"))
--пропущено 10 строк кода
psi.Menu(PluginId,MenuId,-1,-1,0,0,nil,nil,nil,nil,nil,items,N)
Разве тут есть гарантия, что данные доживут до момента их использования?

И последний момент: всегда ли корректно кастить в "void*", не разделяя что там на самом деле требуется принимающим функциям
(const wchar_t* / wchar_t* / char* / и т.д.) ?

Shmuel
Posts: 5919
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 23 times
Been thanked: 233 times

Re: Вопросы по использованию FFI

Post by Shmuel » Mon 24 Feb, 2014 16:45

ffi.cast от "незакреплённой" величины - это скорее всего баг. То, что он не всегда проявляется, тоже понятно. Чтобы стимулировать проявление бага, можно вызвать пару раз collectgarbage("collect") между получением и использованием.

Пример с гуидом - да, видимо баг.

ffi.cast("void*", value) для передачи функциям Windows API / Far API корректен, если value указывает на то, что функция ожидает получить.

User avatar
John Doe
Бюрократ
Posts: 12530
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 33 times
Been thanked: 234 times

Re: Вопросы по использованию FFI

Post by John Doe » Tue 25 Feb, 2014 11:22

Спасибо.

А этот код можно ли заменить на ?
Есть тут какие-то грабли?

И правильно ли я понимаю что ffi.new("wchar_t[?]",BufferLength/2) это то же самое что ffi.new("char[?]",BufferLength)
Т.е. по большому счёту тип не важен, главное выделять BufferLength/ffi.sizeof(type)?

User avatar
HaRT
Moderator
Posts: 9154
Joined: Tue 30 Aug, 2005 17:21
Location: Санкт-Петербург
Has thanked: 90 times
Been thanked: 174 times

Re: Вопросы по использованию FFI

Post by HaRT » Tue 25 Feb, 2014 11:55

John Doe wrote:правильно ли я понимаю что ffi.new("wchar_t[?]",BufferLength/2) это то же самое что ffi.new("char[?]",BufferLength)[...]?
Не знаю, как там в Lua/FFI, а в Си/Си++ это будет корректно только на конкретных платформах. На других же платформах значение Пи может достигать четырёх размер sizeof(wchar_t) может заметно отличаться.
Фар есть инструмент, а не нянька. © 2009 DrKnS

User avatar
John Doe
Бюрократ
Posts: 12530
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 33 times
Been thanked: 234 times

Re: Вопросы по использованию FFI

Post by John Doe » Tue 25 Feb, 2014 12:08

HaRT
Потому я и указал что в общем случае зависит от sizeof.
Но на тех платформах, на которых вообще возможен запуск фара, этим можно пренебречь.
Во всяком случае такой вывод я делаю из примеров кода специалистов:
spell.lua wrote:

Code: Select all

local function ToWChar(str)
  str=win.Utf8ToUtf16(str)
  local result=ffi.new("wchar_t[?]",#str/2+1)
  ffi.copy(result,str)
  return result
end

Shmuel
Posts: 5919
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 23 times
Been thanked: 233 times

Re: Вопросы по использованию FFI

Post by Shmuel » Tue 25 Feb, 2014 12:31

John Doe wrote:А этот код можно ли заменить на ?
Есть тут какие-то грабли?

И правильно ли я понимаю что ffi.new("wchar_t[?]",BufferLength/2) это то же самое что ffi.new("char[?]",BufferLength)
Т.е. по большому счёту тип не важен, главное выделять BufferLength/ffi.sizeof(type)?
1. Граблей не вижу, но не забывать о дополнительном нулевом символе в конце.
2. Правильно, при условии, что ф-ция API получит на вход тот тип указателя, с которым она объявлена (или void*).

User avatar
zg
zero-gravity
Posts: 5651
Joined: Tue 15 Mar, 2005 17:36
Location: riga
Been thanked: 114 times
Contact:

Re: Вопросы по использованию FFI

Post by zg » Tue 25 Feb, 2014 12:43

John Doe wrote:Есть тут какие-то грабли?
потенциально есть грабли с выравниванием.

User avatar
John Doe
Бюрократ
Posts: 12530
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 33 times
Been thanked: 234 times

Re: Вопросы по использованию FFI

Post by John Doe » Tue 25 Feb, 2014 12:56

zg
Т.е. адрес, по которому находится lua-строка, может прийтись не на начало машинного слова?
Выходит не стоит так делать.

Ещё вопрос.
В буфере из примера выше находится C-строка неизвестной длины.
Как лучше всего перевести её в lua-строку?
Очевидно надо использовать ffi.string, но поскольку длина заранее неизвестна, то возможны варианты
- объявить и использовать C.lstrlenW
- перевести в строку весь буфер, и использовать match"(.-)%z"

Почему-то кажется что должен быть более изящный способ.

User avatar
zg
zero-gravity
Posts: 5651
Joined: Tue 15 Mar, 2005 17:36
Location: riga
Been thanked: 114 times
Contact:

Re: Вопросы по использованию FFI

Post by zg » Tue 25 Feb, 2014 18:17

John Doe wrote:Т.е. адрес, по которому находится lua-строка, может прийтись не на начало машинного слова?
в теории, да. на практике, наверное, нет. но кто ж его знает, что случится завтра.
John Doe wrote:- объявить и использовать C.lstrlenW

Почему-то кажется что должен быть более изящный способ.
я так делал в спелере, вроде даже что-то обсуждали тогда, и типа нет вариантов проще.

User avatar
John Doe
Бюрократ
Posts: 12530
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 33 times
Been thanked: 234 times

Re: Вопросы по использованию FFI

Post by John Doe » Tue 25 Feb, 2014 23:50

zg wrote:
John Doe wrote:Т.е. адрес, по которому находится lua-строка, может прийтись не на начало машинного слова?
в теории, да. на практике, наверное, нет. но кто ж его знает, что случится завтра.
Значит и пример с первой страницы не полностью надёжен?
  1. local text = win.Utf8ToUtf16(str)
  2. item.Text = ffi.cast("const wchar_t*", text)
Shmuel wrote:ffi.cast от "незакреплённой" величины - это скорее всего баг.
Нашёл в picture.lua:204 такой код:

Code: Select all

      local delayraw=ffi.cast("PropertyItem*",ffi.new("char[?]",delaysize[0]))

User avatar
zg
zero-gravity
Posts: 5651
Joined: Tue 15 Mar, 2005 17:36
Location: riga
Been thanked: 114 times
Contact:

Re: Вопросы по использованию FFI

Post by zg » Wed 26 Feb, 2014 12:15

John Doe wrote:Значит и пример с первой страницы не полностью надёжен?
вопрос в том, как работает аллокатор строк и ffi.new. возможно там такое выравнивание, что хватит всем.
John Doe wrote:Нашёл в picture.lua:204 такой код:
спасибо, поправил.
update:
тут пишут, что «8 byte alignment is guaranteed» для ffi.new.

User avatar
John Doe
Бюрократ
Posts: 12530
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 33 times
Been thanked: 234 times

Re: Вопросы по использованию FFI

Post by John Doe » Sun 02 Mar, 2014 07:46

Возможно ли через ffi как-то воспользоваться C-функциями far api?

Shmuel
Posts: 5919
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 23 times
Been thanked: 233 times

Re: Вопросы по использованию FFI

Post by Shmuel » Sun 02 Mar, 2014 08:09

John Doe wrote:Возможно ли через ffi как-то воспользоваться C-функциями far api?
Да, для этого даже добавлен файл LuaMacro\farapi.lua.
Для получения указателя на PluginStartupInfo есть ф-ция far.CPluginStartupInfo, нужно cделать ffi.cast() от результата её вызова.

User avatar
John Doe
Бюрократ
Posts: 12530
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 33 times
Been thanked: 234 times

Re: Вопросы по использованию FFI

Post by John Doe » Sun 02 Mar, 2014 11:23

Не могу сообразить как этим воспользоваться.
При попытке ffi.cast("PluginStartupInfo*",far.CPluginStartupInfo()) получаю ошибку declaration specifier expected near 'PluginStartupInfo'

Shmuel
Posts: 5919
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 23 times
Been thanked: 233 times

Re: Вопросы по использованию FFI

Post by Shmuel » Sun 02 Mar, 2014 11:41

Попробуйте "struct PluginStartupInfo*".

User avatar
John Doe
Бюрократ
Posts: 12530
Joined: Wed 27 Apr, 2005 20:42
Has thanked: 33 times
Been thanked: 234 times

Re: Вопросы по использованию FFI

Post by John Doe » Sun 02 Mar, 2014 21:40

Спасибо, так отлично.

Пытаясь углубиться далее понял что документация FFI слишком лаконична, хотя много информации можно выудить из рассылки.

Post Reply

Return to “Нужна помощь”