我正在使用Python C API用C编写一些Python3脚本,其中包含一些计算繁重的部分。当处理int64时,我无法弄清楚如何确保输入数字是未签名的int64。也就是说,如果它小于0。按照official documentation的建议,我正在将PyArg_ParseTuple()
与格式化程序K
一起使用-不会不检查溢出。这是我的C代码:
static PyObject* from_uint64(PyObject* self, PyObject*){
uint64_t input;
PyObject* output;
if (!PyArg_ParseTuple(args, "K", &input)){
return PyErr_Format(PyExc_ValueError, "Wrong input: expected unsigned 64-bit integer.");
}
return NULL;
}
但是,使用负参数调用该函数不会引发任何错误,并且输入数字将转换为无符号。例如,from_uint64(-1)
将产生input=2^64-2
。如预期的那样,因为没有溢出检查。
确定输入数字是否为负(可能是在解析之前)的正确方法是什么?
答案 0 :(得分:1)
您应该使用
unsigned long long input = PyLong_AsUnsignedLongLong(args);
然后您可以通过
进行检查if (PyErr_Occurred()) {
// handle out of range here
}
如果该数字不适合unsigned long long
。
答案 1 :(得分:0)
对@Ctx的答案进行了一些修改:
解决方案是首先将输入解析为对象(因此,不能直接从args
进行解析),然后检查其类型:
static PyObject* from_uint64(PyObject* self, PyObject* args){
PyObject* output;
PyObject* input_obj;
if (!PyArg_ParseTuple(args, "O", &input_obj)){
return PyErr_Format(PyExc_TypeError, "Wrong input: expected py object.");
}
unsigned long long input = PyLong_AsUnsignedLongLong(input_obj);
if(input == -1 && PyErr_Occurred()) {
PyErr_Clear();
return PyErr_Format(PyExc_TypeError, "Parameter must be an unsigned integer type, but got %s", Py_TYPE
(input_obj)->tp_name);
}
此代码符合预期,可用于[0,2 ^ 64-1]中的任何输入,并对边界外的整数以及非法类型(例如浮点数,字符串等)引发错误。