我跟随this answer调用PyDateTime_FromTimestamp
在C ++中创建一个datetime
对象。但是当调用Segmentation fault
时我得到了PyDateTime_FromTimestamp
。
这是我的C ++代码:
#include <python3.6/Python.h>
#include <stdio.h>
#include <python3.6/datetime.h>
#include <sys/time.h>
static PyObject *iGetDateTime_PyFn(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) {
static double doubleValue = 1314761451;
PyObject *floatObj = NULL;
PyObject *timeTuple = NULL;
PyObject *dateTime = NULL;
floatObj = PyFloat_FromDouble(doubleValue);
timeTuple = Py_BuildValue("(O)", floatObj);
printf("timeTuple = %08x\n", (unsigned int)(long long)timeTuple);
printf("PyTuple_Check(timeTuple) = %d\n", PyTuple_Check(timeTuple));
dateTime = PyDateTime_FromTimestamp(timeTuple);
printf("ready to return\n");
return dateTime;
}
static PyMethodDef all_methods[] = {
{ "get_datetime", iGetDateTime_PyFn, METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL }
};
static struct PyModuleDef main_module = {
PyModuleDef_HEAD_INIT,
"cpp",
NULL,
-1,
all_methods
};
PyMODINIT_FUNC PyInit_cpp(void) {
return PyModule_Create(&main_module);
}
我使用以下命令进行编译:
g++ --shared -fPIC -o cpp.so t1.cpp
我的g++
版本是7.3.0
。
在python中,我执行:
import cpp
print(cpp.get_datetime())
然后我得到以下打印内容:
timeTuple = a7934358
PyTuple_Check(timeTuple) = 1
Segmentation fault (core dumped)
我们可以看到timeTuple
已成功构建,并且已作为tuple
检查。但是我们无法到达return
句子。
答案 0 :(得分:2)
根据[GitHub]: python/cpython - (3.6) cpython/Include/datetime.h( $ {PYTHON_SRC_DIR} /Include/datetime.h ):
PyDateTime_FromTimestamp 是预处理器宏 :
#define PyDateTime_FromTimestamp(args) \
PyDateTimeAPI->DateTime_FromTimestamp( \
(PyObject*) (PyDateTimeAPI->DateTimeType), args, NULL)
PyDateTimeAPI 初始化为 NULL (文件中较早的版本)
static PyDateTime_CAPI *PyDateTimeAPI = NULL;
导致 segfault (访问冲突)。
此修复程序需要通过 PyDateTime_IMPORT 宏初始化 PyDateTimeAPI 。
#define PyDateTime_IMPORT \
PyDateTimeAPI = (PyDateTime_CAPI *)PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0)
最初,我在浏览代码时发现了这一点(我是在 getDateTimePyFn 函数中完成的),然后我遇到了[Python 3.Docs]: DateTime Objects(强调是我的)
使用任何这些功能之前,必须将头文件
datetime.h
包含在您的源文件中(请注意,Python.h
不包含头文件),并且宏 PyDateTime_IMPORT < / em>必须被调用,通常是作为模块初始化功能的一部分。
我修改了您的代码,并在 Win 上进行了示例(因为这对我来说比较容易,并且行为可复制)。
cpp.c :
#include <stdio.h>
#include <Python.h>
#include <datetime.h>
#define MOD_NAME "cpp"
static double doubleValue = 1314761451;
static PyObject *getDateTimePyFn(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) {
PyObject *floatObj = NULL,
*timeTuple = NULL,
*dateTime = NULL;
floatObj = PyFloat_FromDouble(doubleValue);
if (!floatObj)
{
return NULL;
}
timeTuple = Py_BuildValue("(O)", floatObj);
Py_XDECREF(floatObj);
if (!timeTuple)
{
return NULL;
}
dateTime = PyDateTime_FromTimestamp(timeTuple);
Py_XDECREF(timeTuple);
return dateTime;
}
static PyMethodDef all_methods[] = {
{ "get_datetime", getDateTimePyFn, METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL }
};
static struct PyModuleDef main_module = {
PyModuleDef_HEAD_INIT,
MOD_NAME,
NULL,
-1,
all_methods
};
PyMODINIT_FUNC PyInit_cpp(void) {
PyDateTime_IMPORT; // @TODO - cfati: !!! This initializes the struct containing the function pointer !!!
return PyModule_Create(&main_module);
}
code.py :
#!/usr/bin/env python3
import sys
import cpp
def main():
print("cpp.get_datetime returned: {:}".format(cpp.get_datetime()))
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
main()
print("Done.")
输出:
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q055903897]> sopr.bat *** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages *** [prompt]> "c:\Install\x86\Microsoft\Visual Studio Community\2015\vc\vcvarsall.bat" x64 [prompt]> dir /b code.py cpp.c [prompt]> cl /nologo /DDLL /MD /I"c:\Install\x64\Python\Python\03.06.08\include" cpp.c /link /NOLOGO /DLL /LIBPATH:"c:\Install\x64\Python\Python\03.06.08\libs" /OUT:cpp.pyd cpp.c Creating library cpp.lib and object cpp.exp [prompt]> dir /b code.py cpp.c cpp.exp cpp.lib cpp.obj cpp.pyd [prompt]> "e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code.py Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32 cpp.get_datetime returned: 2011-08-31 06:30:51 Done.