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

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

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

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

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

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

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

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

Re: luajit в фаре

Post by zg » Thu 08 Aug, 2013 02:56

Latest post of the previous page:

Shmuel wrote:В своих библиотеках можно перед вызовом ffi.cdef проверить, определена ли та или иная константа.
а как?

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

luajit в фаре

Post by Shmuel » Thu 08 Aug, 2013 07:14

zg wrote:а как?
Например, так:
  1. local ffi = require "ffi"
  2. if pcall(ffi.sizeof, "FFI_FARAPI_DEFINED") then return end
  3. ffi.cdef "typedef int FFI_FARAPI_DEFINED"

Acerbic
Posts: 80
Joined: Wed 07 Apr, 2010 12:30
Been thanked: 2 times

Re: luajit в фаре

Post by Acerbic » Sun 11 Aug, 2013 17:00

Shmuel wrote: LuaJIT FFI рассматривает переопределение статических констант и enum'ов как ошибку. На повторное определение функций почему-то не жалуется.
Это в С такая фишка, что объявление и определение - разные вещи, ЕМНИП. Определения повторять нельзя, объявления можно. Для функций заголовок без тела считается только объявлением, а константы и переменные (даже не инициализированные) считаются определениями, если нет специального ключевого слова extern

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

Re: luajit в фаре

Post by Shmuel » Sun 11 Aug, 2013 17:23

Acerbic wrote:Это в С такая фишка, что объявление и определение - разные вещи, ЕМНИП. Определения повторять нельзя, объявления можно. Для функций заголовок без тела считается только объявлением, а константы и переменные (даже не инициализированные) считаются определениями, если нет специального ключевого слова extern
Да, это так, но при использовании в Lua доставляет неудобства: нельзя (без спец-приседаний) запустить скрипт более 1 раза, нельзя перезагрузить модуль.

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

ffi.C и unicode/multibyte ... string

Post by EGez » Sat 14 Dec, 2013 17:39

Что-то никак не получается через FFI протолкнуть кириллический текст без потерь, уже даже к методам научного тыка прибегнуть пришлось ... :(

На примере: MessageBoxW(HWND, LPCWSTR, LPCWSTR, UINT);

Пока пришел к следующему, но в конце текста сообщения мусор, как правильно с ним работать?
  1. -- file encoding UTF-8/65001
  2.  
  3. local ffi = require("ffi")
  4. local C = ffi.C
  5.  
  6. ffi.cdef[[
  7. int MessageBoxA(void *w, const char *txt, const char *cap, int type);
  8. int MessageBoxW(void *w, const wchar_t *txt, const wchar_t *cap, int type);
  9. ]]
  10.  
  11. -- MessageBoxW:
  12. -- 1. Китайский
  13. C.MessageBoxW(nil, 'Кириллический текст', 'AS IS', 1)
  14.  
  15. -- 2. Вроде работает, но в конце строк мусор
  16. C.MessageBoxW(nil, win.Utf8ToUtf16('Кириллический текст'), win.Utf8ToUtf16('Utf8ToUtf16'), 1)
  17.  
  18. -- 3. Снова китай
  19. C.MessageBoxW(nil, win.OemToUtf8('Кириллический текст'), win.OemToUtf8('OemToUtf8'), 1)
  20.  
  21.  
  22. -- MessageBoxA:
  23. -- 4. UTF-8 в ANSI кодировке
  24. C.MessageBoxA(nil, 'Кириллический текст', 'AS IS', 1)
Последний случай (MessageBoxA) у большинства из вас скорее всего будет работать, т.к. locale у вас "случайно" подходящая...

Благодарю

Abs
Posts: 67
Joined: Tue 27 Jul, 2010 12:14
Been thanked: 7 times

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

Post by Abs » Sat 14 Dec, 2013 17:55

EGez wrote:-- 2. Вроде работает, но в конце строк мусор
C.MessageBoxW(nil, win.Utf8ToUtf16('Кириллический текст'), win.Utf8ToUtf16('Utf8ToUtf16'), 1)

Code: Select all

C.MessageBoxW(nil, win.Utf8ToUtf16('Кириллический текст\0'), win.Utf8ToUtf16('Utf8ToUtf16\0'), 1)
?

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 » Sat 14 Dec, 2013 19:09

Abs wrote:

Code: Select all

C.MessageBoxW(nil, win.Utf8ToUtf16('Кириллический текст\0'), win.Utf8ToUtf16('Utf8ToUtf16\0'), 1)
?
Спасибо, сработало.

Но меня терзают смутные сомнения: Почему jit их автоматически не завершает нулями при передаче в контекст c runtime? Это же стандарт в C/C++, именно поэтому мне и не пришла такая идея в голову.
Это workaround или стандартное поведение? Где-нибудь описано?

Спасибо

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

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

Post by zg » Sat 14 Dec, 2013 19:37

EGez wrote:Но меня терзают смутные сомнения: Почему jit их автоматически не завершает нулями при передаче в контекст c runtime?
а как он должен догадаться?

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

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

Post by Shmuel » Sat 14 Dec, 2013 19:47

EGez wrote:Но меня терзают смутные сомнения: Почему jit их автоматически не завершает нулями при передаче в контекст c runtime? Это же стандарт в C/C++, именно поэтому мне и не пришла такая идея в голову.
Это workaround или стандартное поведение? Где-нибудь описано?
LuaJIT обрабатывает то, что ему передано, и это правильно.

Данное поведение проистекает от того, что, в отличие от Си-строк, строки в Lua не содержат завершающего нуля (хотя во внутренностях Lua он имеется, но только один нулевой байт, а не два, как нужно для UTF-16).

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 » Sat 14 Dec, 2013 20:16

Shmuel wrote: LuaJIT обрабатывает то, что ему передано, и это правильно.

Данное поведение проистекает от того, что, в отличие от Си-строк, строки в Lua не содержат завершающего нуля (хотя во внутренностях Lua он имеется, но только один нулевой байт, а не два, как нужно для UTF-16).
Хм.. Я кажется понял в чем дело. Скорее дело не в том, что Lua не использует zero termination.
Поскольку Lua стринги свои не различает на широкие и узкие, ;-) в C runtime оно, похоже, передается как char[]/byte[] совершенно не задумываясь о семантике содержимого и все-таки завершенным одним \0 (т.к. char). Поэтому ANSI функции работают нормально... А функция же, которая получает от сего пойнтер параметром, ожидает, что это utf16 и интерпретирует его соответственно, ну и обламывается на одном \0.

Спасибо!

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

ffi.C и unicode/multibyte ... string

Post by John Doe » Mon 16 Dec, 2013 09:57

EGez wrote:Что-то никак не получается через FFI протолкнуть кириллический текст без потерь, уже даже к методам научного тыка прибегнуть пришлось ... :(

На примере: MessageBoxW(HWND, LPCWSTR, LPCWSTR, UINT);

Последний случай (MessageBoxA) у большинства из вас скорее всего будет работать, т.к. locale у вас "случайно" подходящая...

Благодарю
Что тут может быть не так?

Code: Select all

C:\APPs\Far3\lua51x.exe: C:\APPs\Far3\Profile\Macros\2check\ffi\MessageBoxW.lua:13: bad argument #2
to 'MessageBoxW' (cannot convert 'string' to 'const unsigned short *')
stack traceback:
        [C]: in function 'MessageBoxW'
        C:\APPs\Far3\Profile\Macros\2check\ffi\MessageBoxW.lua:13: in main chunk
        [C]: at 0x00407bbc
Проблема только с MessageBoxW, а MessageBoxA отрабатывает нормально

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

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

Post by Shmuel » Mon 16 Dec, 2013 10:14

John Doe wrote:Что тут может быть не так?

Code: Select all

C:\APPs\Far3\lua51x.exe: C:\APPs\Far3\Profile\Macros\2check\ffi\MessageBoxW.lua:13: bad argument #2
to 'MessageBoxW' (cannot convert 'string' to 'const unsigned short *')
stack traceback:
        [C]: in function 'MessageBoxW'
        C:\APPs\Far3\Profile\Macros\2check\ffi\MessageBoxW.lua:13: in main chunk
        [C]: at 0x00407bbc
В тексте ошибки ясно сказано, что не так. wchar_t - это unsigned short.
Почитайте несколько сообщений, начиная от http://forum.farmanager.com/viewtopic.p ... 45#p111545, там есть примеры.

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

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

Post by John Doe » Mon 16 Dec, 2013 10:25

В данном случае я не пытался освоить FFI, а всего лишь хотел запустить готовый пример из первого сообщения.
Автор представляет его как рабочий, поэтому мне показалось что у меня какая-то проблема с инсталляцией.

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

ffi.C и unicode/multibyte ... string

Post by Shmuel » Mon 16 Dec, 2013 10:34

Можно так:
  1. C.MessageBoxW(nil, ffi.cast("void*", win.Utf8ToUtf16('Кириллический текст\0')),
  2.    ffi.cast("void*", win.Utf8ToUtf16('Utf8ToUtf16\0')), 1)

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

ffi.C и unicode/multibyte ... string

Post by EGez » Mon 16 Dec, 2013 17:03

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

На самом деле у меня работающий пример выглядит так:
  1. -- file encoding UTF-8/65001
  2.  
  3. local ffi = require 'ffi'
  4. local C = ffi.C
  5.  
  6. local function utf16(str)
  7.     return win.Utf8ToUtf16(str .. '\0')
  8. end
  9.  
  10. ffi.cdef[[
  11. int MessageBoxW(void *w, const char *txt, const char *cap, int type);
  12. ]]
  13.  
  14. C.MessageBoxW(nil, utf16('Тут у нас сообщение (message)'), utf16('Тут у нас титель (title)'), 1)
Я конечно понимаю, что так делать не совсем чисто, но для машины-то без разницы, будь то char* byte* или short*.

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

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

Post by HaRT » Mon 16 Dec, 2013 17:06

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

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

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

Post Reply

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