Search code examples
luaffiluajit

Luajit ffi how to call funcitons in time.h?


I tried to call function tan of math.h this way (directly copy the declaration) and it works:

local ffi = require("ffi")
ffi.cdef[[
    double tan(double x);
]]
print(ffi.C.tan(45))

But when I tried to call the function localtime of time.h the same way:

local ffi = require("ffi")
ffi.cdef[[
    struct tm *localtime(const time_t *tp);
]]
print(ffi.C.localtime(1234544))

And get error:

lua: C:\Users\xiang\Desktop\bm.lua:4: declaration specifier expected near 'time_t'
stack traceback:
    [C]: in function 'cdef'
    C:\Users\xiang\Desktop\bm.lua:4: in main chunk
    [C]: at 0x00401f00
[Finished in 0.1s with exit code 1]

I've checked the official manual this and this but still confused.


Solution

  • Every function you would like to call from FFI, it needs to be defined before. If not LuaJIT does not how to parse a FFI function call, how to do data-type conversion from Lua to C (and viceversa), etc.

    Keeping that in my mind, to make your code work you would need to define time_t and struct tm. time_t is generally defined as a signed integer. You can find the definition of struct tm in localtime docs (man localtime).

    ffi.cdef[[
       struct tm {
          int tm_sec;    /* Seconds (0-60) */
          int tm_min;    /* Minutes (0-59) */
          int tm_hour;   /* Hours (0-23) */
          int tm_mday;   /* Day of the month (1-31) */
          int tm_mon;    /* Month (0-11) */
          int tm_year;   /* Year - 1900 */
          int tm_wday;   /* Day of the week (0-6, Sunday = 0) */
          int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */
          int tm_isdst;  /* Daylight saving time */
       };
       struct tm *localtime(const int32_t *tp);
    ]]
    

    In addition, function localtime expects a pointer value, not a constant integer. So it would be necessary to pass a c-data pointer storing an integer to localtime. There's a sort of LuaJIT idiom for that.

    local time = ffi.new("int32_t[1]")
    time[0] = 1234544
    local tm = C.localtime(time)
    

    Since arrays and pointers in C, although not the exactly same, are interchangeable in most cases.

    Lastly, you cannot print a struct tm directly. Should store it into a variable and print out the fields you're interested.

    print(tm.tm_sec)