Как получить доступ к нескольким возвращаемым переменным, скомпилированным в python

#python #c #segmentation-fault #stdtuple #ctype

#python #c #ошибка сегментации #ctypes #стандартный набор

Вопрос:

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

Ниже приведен код c с двумя возвращаемыми переменными с помощью метода tuple

 std::tuple<double, double> Cassie2d::Step(ControllerTorque* action)
{
  dyn_model_.setState(mj_data_->qpos, mj_data_->qvel);
  dyn_state_.UpdateDynamicState(amp;dyn_model_);

  mju_copy(mj_data_->ctrl, action->torques, nU);
  mj_step(mj_model_, mj_data_);
  return std::make_tuple(mj_data_->qacc,mj_data_->time);
  Render();
}
  

Ниже приведен метод python, который я применил, поскольку обе возвращаемые переменные имеют двойной тип.

 lib.StepTorque.argtypes = [ctypes.c_void_p, ctypes.POINTER(ControllerTorque)]
lib.StepTorque.restype = ctypes.c_double
  

Я предполагаю, что restype это не просто равно ctypes.c_double , потому что это сработало для одной возвращаемой переменной и может не сработать для двух возвращаемых переменных.

Очень признателен за помощь!

Комментарии:

1. Предоставьте некоторые подробности — какую библиотеку python вы используете? Ошибка сегментации предполагает, что вы можете инициализировать python, но не некоторые дополнительные модули (возможно, numpy?). К нескольким возвращаемым переменным обычно можно получить доступ следующим образом: VarA, VarB = function_name(arguments)

2. lib = cdll. LoadLibrary(‘../../bin/libcassie2d.so’). Файл c , скомпилированный в динамическую библиотеку, которая libcassie2d.so приведенный выше код загружает библиотеку на python, я мог бы загрузить одну возвращаемую переменную, а не две переменные, которые я определил в c

3. ctypes предназначен для C , а не C . Он не понимает классы C и нуждается в стандартных типах C, таких как double , not std::tuple<double, double> .

Ответ №1:

С return std::make_tuple(mj_data_->qacc,mj_data_->time) вашим созданием структуры, которая содержит две переменные, определенные в круглых скобках. Если функция будет вызываться из собственного кода C , вы должны иметь возможность распаковать ее с помощью std: tie, eq:

 double a, b;
std::tie(a,b) = Step(arg);
  

Однако вам нужно вызвать его непосредственно из python, который имеет совершенно другой синтаксис для возврата нескольких переменных (пара или кортеж C — это своего рода обход отсутствующей функциональности). Я вижу два варианта в python.

  1. Дайте вашей функции C два обратных вызова в python и отправляйте переменные отдельно таким образом:

     void Cassie2d::Step(ControllerTorque* action, callback1, callback2)
    {
    dyn_model_.setState(mj_data_->qpos, mj_data_->qvel);
    dyn_state_.UpdateDynamicState(amp;dyn_model_);
    
    mju_copy(mj_data_->ctrl, action->torques, nU);
    mj_step(mj_model_, mj_data_);
    callback1(mj_data_->qacc);
    callback2(mj_data_->time);
    Render();
    }
      
  2. (Рекомендуется) Вы можете попробовать использовать встроенную опцию python для обслуживания нескольких возвращаемых данных. Оставил вашу функцию C в ее начальной форме и вызывал на python таким образом:

     VarA, VarB = Step(action)
      

    Я предполагаю, что у вас есть ссылка на Cassie2d::Step(ControllerTorque* action) метод в вашем коде python, однако вы предоставили очень маленький фрагмент.

Комментарии:

1. lib = cdll. LoadLibrary(‘../../bin/libcassie2d.so’) c_double_p = ctypes. УКАЗАТЕЛЬ (ctypes.c_double) Эти две строки кода использовались для доступа к динамической библиотеке, которая также была скомпилирована из кода c , lib. Пошаговая инструкция. argtypes = [ctypes.c_void_p, ctypes. УКАЗАТЕЛЬ (ControllerTorque)] библиотека. StepTorque.restype = None предназначен для определения входного аргумента и возвращаемых типов с использованием ctypes, не могли бы вы, пожалуйста, сказать мне, что делать с restype пожалуйста, я действительно ценю вашу помощь!

2. Я не уверен, как работает ваш код. Итак, строка lib.StepTorque.restype = ctypes.c_double извлекает значение? Если да, то какая часть этого кода ссылается на переменную name od, в которой возвращаемое значение является хранилищем?