From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from m12-17.163.com (m12-17.163.com [220.181.12.17]) by sourceware.org (Postfix) with ESMTPS id C690C385041C for ; Fri, 19 Mar 2021 03:10:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org C690C385041C Received: from [192.168.0.101] (unknown [183.211.164.254]) by smtp13 (Coremail) with SMTP id EcCowADHw7DeFVRg_noPqw--.5679S2; Fri, 19 Mar 2021 11:09:19 +0800 (CST) Subject: Re: How to call 'printf' using libffi? To: "Kaz Kylheku (libffi)" <382-725-6798@kylheku.com> Cc: Anthony Green , libffi-discuss References: <00aed94e-6f76-f6d7-9878-a3eb50dce543@163.com> <0b7f2827-e209-2c58-7118-9fec4770ae1c@163.com> <8b91422069c635427e0e3f57c1814f47@mail.kylheku.com> From: ShaJunxing Message-ID: Date: Fri, 19 Mar 2021 11:09:18 +0800 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.8.1 MIME-Version: 1.0 In-Reply-To: <8b91422069c635427e0e3f57c1814f47@mail.kylheku.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit X-CM-TRANSID: EcCowADHw7DeFVRg_noPqw--.5679S2 X-Coremail-Antispam: 1Uf129KBjvJXoWxAw4fAr1rZw45tw18Gw4DJwb_yoW5ur47pa 95JFWakF4kJr42ywnFyw4vvw1F93yYqFWayFZ0q3y2yFsrXFyxtr48CFnYva4DCryYgr1a vF4jq3s3C3Z8AaDanT9S1TB71UUUUUUqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07jm6wtUUUUU= X-Originating-IP: [183.211.164.254] X-CM-SenderInfo: xvkdy3xq0l0wi6rwjhhfrp/1tbiLh9aP1SIsqnz+AAAsY X-Spam-Status: No, score=1.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, NICE_REPLY_A, RCVD_IN_BARRACUDACENTRAL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=no autolearn_force=no version=3.4.2 X-Spam-Level: * X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libffi-discuss@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libffi-discuss mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 19 Mar 2021 03:10:13 -0000 在 2021/3/19 上午10:36, Kaz Kylheku (libffi) 写道: > 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 > ? > > 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 >> #include >> 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. Thank you for your detailed answer, it's very kind of you. I'm not very good at C and was always thought var args are in fact macros and will be fixed length after compiling, now I realized it is a special mechanism not as simple as macros. I'll do more studying. Thank you so much.😁