Функция всегда возвращает бессмысленное значение

Я пишу функции C, которые будут вызываться cffi в pypy3. Однако обернутые функции всегда возвращают бессмысленное значение в pypy3, независимо от того, какое истинное возвращаемое значение.

Вывод функции printf() говорит мне, что в функции C все работает нормально, но возвращаемое значение в pypy3 изменилось.

Функция C записывается следующим образом:

double test(){
    return 5.12;
}

double test2(){
    double tmp=test();
    printf("!!!!!!!%f\n",tmp);
    return tmp;
}

Сценарий сборки cffi выглядит следующим образом:

from cffi import FFI
ffibuilder = FFI()

ffibuilder.set_source("_faststr_cffi",
                      """
                        #include <Python.h>
                        #include "stdint.h"
                        #include <string.h>
                        typedef uint32_t char32_t;
                      """,
                      sources=['faststr_purec.c']
                      )   # library name, for the linker

ffibuilder.cdef("""
double test();
double test2();
""")

if __name__ == "__main__":
    ffibuilder.compile(verbose=True)

Я попытался вызвать test2() в консоли pypy3:

>>>> from _faststr_cffi import lib
>>>> lib.test2()
!!!!!!!5.120000
16.0

printf говорит мне, что возвращаемое значение должно быть 5.120000, но в pypy3 оно вернуло 16.0.

Я нашел подсказку: если я изменю строку в функции test2() printf, возвращаемое значение test2 в pypy3 изменится.

Обновление: результат в cpython 3.6.7 такой же, так что это не проблема pypy3


person Jay    schedule 25.07.2019    source источник
comment
Странный вопрос, но всегда ли это количество написанных символов? Потому что здесь это выглядит так   -  person Edward Minnix    schedule 25.07.2019
comment
@EdwardMinnix Действительно, это хороший улов, который приводит к выявлению причины плохого поведения.   -  person Ctx    schedule 25.07.2019


Ответы (1)


Проблема заключается в следующем:

Здесь вы объявляете функции test() и test2():

ffibuilder.cdef("""
double test();
double test2();
""")

Эти объявления предназначены только для того, чтобы интерфейс cffi знал, какие возвращаемые значения использовать. Но объявления собственных функций c test() и test2() отсутствуют. Таким образом, они неявно объявляются возвращающими int!

Теперь, когда вызывается функция test() (которая неявно объявлена ​​возвращающей int) из test2

double tmp = test();

return tmp;

скомпилированный код считывает неправильный регистр (потому что он ищет целочисленное значение) и преобразует его в двойное, возвращая его в результате. Так случилось, что последний целочисленный результат был результатом printf(), который является длиной напечатанной строки. Из-за этого вы получаете результат 16 в вашем случае.

Исправление состоит в том, чтобы правильно объявить функции test() и test2():

ffibuilder.set_source("_faststr_cffi",
                  """
                    #include <Python.h>
                    #include "stdint.h"
                    #include <string.h>
                    typedef uint32_t char32_t;
                    double test();
                    double test2();
                  """,
                  sources=['faststr_purec.c']
                  )   # library name, for the linker

Тогда он должен работать так, как ожидалось.

person Ctx    schedule 25.07.2019
comment
Я думаю, вы правы. Но не могли бы вы подробнее объяснить, почему printf печатает правильное возвращаемое значение 5.120000? - person Jay; 25.07.2019
comment
@Jay Это вопрос соглашений о вызовах. test() возвращает двойное значение в регистре A, но test2() ищет целое число в регистре B, поскольку test() (неявно) объявлено возвращающим целое число. Целое число, хранящееся в регистре B, является возвращаемым значением printf(), которое не перезаписывается перед возвратом из test(). - person Ctx; 27.07.2019