public inbox for libffi-discuss@sourceware.org
 help / color / mirror / Atom feed
From: "Kaz Kylheku (libffi)" <382-725-6798@kylheku.com>
To: ShaJunxing <shajunxing@163.com>
Cc: Anthony Green <green@moxielogic.com>,
	libffi-discuss <libffi-discuss@sourceware.org>
Subject: Re: How to call 'printf' using libffi?
Date: Thu, 18 Mar 2021 19:36:40 -0700	[thread overview]
Message-ID: <8b91422069c635427e0e3f57c1814f47@mail.kylheku.com> (raw)
In-Reply-To: <0b7f2827-e209-2c58-7118-9fec4770ae1c@163.com>

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.


  reply	other threads:[~2021-03-19  2:36 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-18 14:04 ShaJunxing
2021-03-18 15:25 ` Anthony Green
2021-03-19  2:08   ` ShaJunxing
2021-03-19  2:36     ` Kaz Kylheku (libffi) [this message]
2021-03-19  3:09       ` ShaJunxing
2021-03-19 10:13   ` Andrew Haley
2021-03-19 11:01     ` Anthony Green
2021-03-19 11:43       ` Andrew Haley
2021-03-20 22:40         ` Anthony Green
2021-03-20 23:56           ` Anthony Green
2021-03-22 10:36             ` Andrew Haley
2021-03-19 11:26     ` Jarkko Hietaniemi
2021-03-19 11:33       ` Anthony Green

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8b91422069c635427e0e3f57c1814f47@mail.kylheku.com \
    --to=382-725-6798@kylheku.com \
    --cc=green@moxielogic.com \
    --cc=libffi-discuss@sourceware.org \
    --cc=shajunxing@163.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).