Python C API检查int64是否未签名

时间:2018-10-05 14:59:44

标签: python c

我正在使用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。如预期的那样,因为没有溢出检查。

确定输入数字是否为负(可能是在解析之前)的正确方法是什么?

2 个答案:

答案 0 :(得分:1)

您应该使用

unsigned long long input = PyLong_AsUnsignedLongLong(args);

然后您可以通过

进行检查
if (PyErr_Occurred()) {
    // handle out of range here
}

如果该数字不适合unsigned long long

另请参阅the Python 3 API documentation on Integer Objects

答案 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]中的任何输入,并对边界外的整数以及非法类型(例如浮点数,字符串等)引发错误。