在Cython中编译时获取整数的大小

时间:2013-04-02 13:34:05

标签: cython

是否可以,如果是,如何确定Cython中整数数据类型的大小(以位为单位)?

我正在尝试做这样的事情,以获得整数大小:

cdef WORD_BITS = 0
IF sizeof(unsigned long long) == 8:
    WORD_BITS = 64
    DEF VECTOR_LENGTH_SHIFT_AMOUNT = 6
ELSE:
    WORD_BITS = 32
    DEF VECTOR_LENGTH_SHIFT_AMOUNT = 5

ctypedef unsigned long long word_t

cdef int vector_length(size_t bit_size):

    cdef size_t size = bit_size >> VECTOR_LENGTH_SHIFT_AMOUNT
    if size << VECTOR_LENGTH_SHIFT_AMOUNT < bit_size:
        size += 1
    return size

cdef class BitVector(object):

    cdef size_t length
    cdef size_t array_size
    cdef word_t *array

    def __cinit__(self, size_t size):
        self.length = size
        self.array_size = vector_length(size)
        self.array = <word_t *>calloc(self.array_size, sizeof(word_t))

    def __dealloc__(self):
        free(self.array)

我需要处理数组元素的单个位和元素本身,因此我必须知道它们包含多少位(计算正确的掩码/移位)。尝试编译上面的代码会产生:

$python setup.py build_ext --inplace
Compiling bitvector.pyx because it changed.
Cythonizing bitvector.pyx

Error compiling Cython file:
------------------------------------------------------------
...
cimport cython


# check whether we are running on a 64 or 32 bit architecture.
cdef WORD_BITS = 0
IF sizeof(unsigned long long) == 8:
  ^
------------------------------------------------------------

bitvector.pyx:7:3: Invalid compile-time expression

Traceback (most recent call last):
  File "setup.py", line 6, in <module>
    ext_modules=cythonize('bitvector.pyx')
  File "/usr/lib/python2.7/dist-packages/Cython/Build/Dependencies.py", line 673, in cythonize
    cythonize_one(*args[1:])
  File "/usr/lib/python2.7/dist-packages/Cython/Build/Dependencies.py", line 737, in cythonize_one
    raise CompileError(None, pyx_file)
Cython.Compiler.Errors.CompileError: bitvector.pyx

是否有可行的替代方案?

我知道有一个stdint.h标头应该定义整数类型,但我想不出一种方法来使用它,因为:

  • 我不知道如何检查类型是否定义(例如,如何在cython中编写IF uint64_t is not defined:。)。
  • Cython的文档说明DEF和编译器定义的内容只能在IF中检查,因此我怀疑无论如何我都能使用stdint.h

似乎这在Cython中是不可行的,因为我想要进行的检查只能在从C编译到机器代码时执行,而不能从cython编译到C。

现在我想知道:是否可以编写一个cython扩展,以便在C源代码中添加这种检查?

我的意思是,我可以以某种方式写道:

cdef WORD_BITS = 0
IF sizeof(unsigned long long) == 8:
    WORD_BITS = 64
    DEF VECTOR_LENGTH_SHIFT_AMOUNT = 6
ELSE:
    WORD_BITS = 32
    DEF VECTOR_LENGTH_SHIFT_AMOUNT = 5

ctypedef unsigned long long word_t

以这种方式,这个IF“不是由Cython处理的,但它是通过并在最终的C文件中传递的是等效的代码吗?

1 个答案:

答案 0 :(得分:1)

我不会使用预处理器来定义大小和移位值,而是会稍微更改vector_length函数,以便它可以直接使用sizeof。 Cython将正确翻译sizeof运算符,编译器将在编译时替换该类型的实际大小。有关使用sizeofCHAR_BIT获取正确的矢量大小的详细信息,请参阅glibc文档中的此部分:https://www.gnu.org/software/libc/manual/html_node/Width-of-Type.html

from libc.stdlib cimport calloc, free
from libc.limits cimport CHAR_BIT

ctypedef unsigned long long word_t

cdef size_t vector_length(size_t bit_size):
    cdef size_t bits_per_word = CHAR_BIT*sizeof(word_t)
    return (bit_size + bits_per_word - 1) / bits_per_word

cdef class BitVector(object):
    cdef size_t length
    cdef size_t array_size
    cdef word_t *array

    def __cinit__(self, size_t size):
        self.length = size
        self.array_size = vector_length(size)
        self.array = <word_t *>calloc(self.array_size, sizeof(word_t))

    def __dealloc__(self):
        free(self.array)

值得注意的是unsigned long long至少为64位(https://en.wikipedia.org/wiki/C_data_types)。您的代码似乎假设它可以 64或32位,但在符合标准的编译器中,它只能是64位或更多。