How to call 'printf' using libffi?
Kaz Kylheku (libffi)
382-725-6798@kylheku.com
Fri Mar 19 02:36:40 GMT 2021
On 2021-03-18 19:08, ShaJunxing via Libffi-discuss wrote:
> Yesterday after sending email I also realized maybe different
> parameters needs different cif, and I did some experiments, it exactly
> works. But I got two more problems. The first is, I found
> ffi_prep_cif() works fine in this situation, so what is
> ffi_prep_cif_var() different from?
Note that what you are saying is exactly analogous to this:
"When I declare printf like this:
extern int printf(const char *fmt, char *arg);
everything works; I can call it as
printf("Hello, %s!\n", name);
and I get the expected output.
why do I have to have a correct variadic prototype by including
<stdio.h>?
It might look like it's working, but it's undefined behavior;
it is not required to work and could prove to be nonportable.
Variadic functions do not necessarily pass arguments the same way
as ordinary functions. In order for libffi to build the correct
parameter passing mechanism for the descriptor, it needs to be
informed that the target function is variadic.
Then, depending on the target architecture, the libffi code
might do some things differently for calling that function.
Those different things might depend on how many arguments
there are and what types.
> The second is, I found printf()
> cannot properly handle float type in my machine, my code is:
Note that when argument expressions of float type are passed
as the trailing arguments of a variadic function, they are
promoted to type double. That's a C language rule.
The rule also applies to old style functions with undeclared
parameter lists,e .g.
int old_style();
float f = 3.14;
old_style(f); /* promoted to double! */
/* definition must be this */
int old_style(arg)
double arg;
{
}
The %f conversion specifier in printf does not mean "float".
It means "fixed digit format". There are two other formats:
%e, exponential and %g, general (which chooses exponential
or fixed digit).
All of these take an argument of type double.
>
> #include <ffi.h>
> #include <stdio.h>
> intmain() {
> ffi_cif cif;
> ffi_type *atypes[2] = {&ffi_type_pointer, &ffi_type_float};
> if(ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint, atypes) ==
> FFI_OK) {
> char*s = "hello %f\n";
> floatf = 3.14;
> void*avalues[2] = {&s, &f};
> ffi_arg rvalue;
> ffi_call(&cif, (void*)printf, &rvalue, avalues);
> }
> return0;
> }
>
> It always outputs zero (maybe other unexpected result). I changed the
> second argument to double, char *, int, long ... all correct, except
> float.
Not only must the FFI type be ffi_type_double, but you must make sure
that the object which the corresponding argument points to is of
type double. FFI doesn't perform any conversion; it has no idea:
there is just a void * pointing at an argument object which is expected
to match the exact type that the type descriptor states.
More information about the Libffi-discuss
mailing list