Вызов функции C в Python и возврат 2 значений

Я пытаюсь выяснить, как вернуть 2 значения из функции C, которую я вызвал в python. Я прочитал материалы в Интернете и использую структуру для вывода двух переменных. Я могу выводить переменные, когда вызываю эту функцию в том же файле C. Однако, когда я пытаюсь вызвать его в python, он по-прежнему возвращает только одно значение.

Это мой код на C:

struct re_val {

    double predict_label;
    double prob_estimates;  

};

struct re_val c_func(const char* dir, double a, double b, double c, double d )
{
    double x[] = {a,b,c,d};

    printf ("x[0].index: %d \n", 1);
    printf ("x[0].value: %f \n", x[0]);

    printf ("x[1].index: %d \n", 2);
    printf ("x[1].value: %f \n", x[1]);

    printf ("x[2].index: %d \n", 3);
    printf ("x[2].value: %f \n", x[2]);

    printf ("x[3].index: %d \n", 4);
    printf ("x[3].value: %f \n", x[3]);

    printf ("\nThis is the Directory: %s \n", dir); 

    struct re_val r;
    r.predict_label = 5.0;
    r.prob_estimates = 8.0;   

    return r;

}

Это мой код Python:

calling_function = ctypes.CDLL("/home/ruven/Documents/Sonar/C interface/Interface.so")
calling_function.c_func.argtypes = [ctypes.c_char_p, ctypes.c_double, ctypes.c_double, ctypes.c_double, ctypes.c_double]
calling_function.c_func.restype =  ctypes.c_double
q = calling_function.c_func("hello",1.3256, 2.45, 3.1248, 4.215440)
print q

В настоящее время, когда я запускаю свой файл python в терминале, он выводит следующее:

x[0].index: 1 
x[0].value: 1.325600 

x[1].index: 2 
x[1].value: 2.450000 

x[2].index: 3 
x[2].value: 3.124800 

x[3].index: 4 
x[3].value: 4.215440 

This is the Directory: hello 

5.0

Вместо этого я хотел бы вывести это:

x[0].index: 1 
x[0].value: 1.325600 

x[1].index: 2 
x[1].value: 2.450000 

x[2].index: 3 
x[2].value: 3.124800 

x[3].index: 4 
x[3].value: 4.215440 

This is the Directory: hello 

5.0
8.0

Не знаю, сработает этот код или нет, но. проверьте эту ссылку. это может быть вам полезно. gist.github.com/Overdrivr/cdd58cea15d7e28c50ea

Junhee Shin 05.07.2018 10:29

Проблема в calling_function.c_func.restype = ctypes.c_double. Вы, по сути, говорите ctypes, что тип результата функции - c_double, тогда как функция из вашей библиотеки c не возвращает double, она возвращает struct re_val.

hetepeperfan 05.07.2018 11:02

@hetepeperfan Я подумал об этом, но не смог найти способ изменить call_function.c_func.restype для возврата структуры, поскольку ctypes.c_struct не существует.

Ruven Guna 05.07.2018 11:12
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
3
548
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш код C в порядке, проблема, с которой вы столкнулись, заключается в том, как вы используете python ctypes. Вы должны сказать, что функция возвращает struct re_val, а не double:

calling_function.c_func.restype =  ctypes.c_double

Вышеупомянутое заставляет функцию возвращать одно двойное значение в глазах ctypes. Вы должны сообщить python, что функция возвращает структуру:

import ctypes as ct

# Python representation of the C struct re_val
class ReVal(ct.Structure):
    _fields_ = [("predict_label", ct.c_double),("prob_estimates", ct.c_double)]

calling_function = ctypes.CDLL("/home/ruven/Documents/Sonar/C interface/Interface.so")
calling_function.c_func.argtypes = [ctypes.c_char_p, ctypes.c_double, ctypes.c_double, ctypes.c_double, ctypes.c_double]
# and instead of c_double use:
calling_function.c_func.restype = ReVal

Таким образом вы сообщаете ctypes python, что функция возвращает агрегированный объект, который является подклассом ctypes.Structure, который соответствует struct re_val из библиотеки c.

ПРИМЕЧАНИЕ Будьте очень осторожны с argtypes и restype, если вы используете их неправильно, интерпретатор python легко выйдет из строя. Тогда вы получите segfault вместо хорошей трассировки.

Привет, к сожалению, когда я запускаю программу, она выдает следующее сообщение: <__ main __. ReVal object at 0x7fb3bd1e0560>

Ruven Guna 09.07.2018 03:13

Да, это верно, но это структура, возвращаемая ctypes, она по-прежнему является агрегатом. Таким образом, возвращаемый объект имеет два поля: «pred_label» и «prob_estimates». Таким образом, вы можете получить к ним доступ через q.predict_label и q.prob_estimates. Обычно вам нужно предпринять некоторые дополнительные шаги для извлечения значений из структуры.

hetepeperfan 10.07.2018 10:34

Другие вопросы по теме