Cython封装utarray库时遇‘expected expression before do’错误求助
The root cause of your error is that utarray_new/utarray_push_back/utarray_free are not actual C functions—they're do-while wrapped macros. When you declared them as regular functions in your .pxd file, Cython treated them as function calls and generated code that tries to use them in an expression context (like wrapping them in (void)(...)). Since do-while blocks are statements (not expressions), the compiler throws a syntax error.
Here's a step-by-step fix:
1. Correct the .pxd Declaration
Update your src/array.pxd to properly reflect the macro behavior, using pointer references for utarray_new (since it modifies the input pointer directly) and declaring all macros as void-type operations:
cdef extern from "src/utarray.h": ctypedef struct UT_icd: size_t sz void (*init)(void* elt) void (*copy)(void* dst, const void* src) void (*dtor)(void* elt) ctypedef struct UT_array: pass const UT_icd ut_int_icd # Use pointer references to match macro's assignment behavior void utarray_new(UT_array*& a, UT_icd* icd) nogil int utarray_len(UT_array* a) nogil void* utarray_eltptr(UT_array* a, int j) nogil void utarray_push_back(UT_array* a, void* p) nogil void utarray_free(UT_array* a) nogil
Declaring the UT_icd members explicitly helps Cython understand the macro's internal logic better, but you can leave the struct empty if you don't need direct access.
2. Fix the Cython Test Code
Adjust your src/array_test.pyx to use the corrected declarations, and initialize the pointer to avoid undefined behavior:
cimport src.array as cn import numpy as np def main(): cdef cn.UT_array *found = NULL # Initialize pointer to NULL # Pass found directly (Cython handles the pointer reference) cn.utarray_new(found, &(cn.ut_int_icd)) cdef long[::1] indexes = np.array(range(10, 20), dtype=np.long) for i in range(10): # Cast long* to void* to match utarray_push_back's parameter cn.utarray_push_back(found, <void*>&(indexes[i])) # Optional: Verify the array works as expected cdef int length = cn.utarray_len(found) print(f"Array length: {length}") for j in range(length): cdef long* val = <long*>cn.utarray_eltptr(found, j) print(f"Element {j}: {val[0]}") cn.utarray_free(found) return
3. Update the Build Script
Ensure your setup.py includes the correct include directory for utarray.h:
from distutils.core import setup from setuptools import find_packages, Extension from Cython.Build import cythonize extensions = [ Extension( "src.array_test", ["src/array_test.pyx"], include_dirs=["src"], # Critical: lets the compiler find utarray.h ) ] setup( name="uthash", packages=find_packages(), ext_modules=cythonize(extensions), package_data={'': ['*.pyx', '*.pxd', '*.h']}, )
Why This Works
- By declaring
utarray_newwith a pointer reference (UT_array*& a), Cython understands that the macro modifies the input pointer directly, generating code that uses the macro as a standalone statement instead of an expression. - Removing the incorrect return type from macro declarations eliminates the
(void)(...)wrapper that caused the syntax error. - Explicitly casting the element pointer to
void*matches the macro's expected parameter type.
内容的提问来源于stack exchange,提问作者The Unfun Cat

