How to Fix Python‑ctypes Return Value Errors When Calling Go Libraries
This article explains why Python's ctypes returns incorrect values when invoking Go-compiled shared libraries, shows how to map C types correctly, and provides step‑by‑step code examples for handling both integer and string return values using proper restype declarations.
1. Introduction
In a previous article we called Go code from Python using a compiled .so file, which improved performance but produced unexpected return values. This follow‑up investigates the cause and presents a complete solution.
2. Why Return Value Errors Occur
The problem originates from the .h header generated by the Go compiler. It defines C‑compatible types for Go functions, and the default ctypes mapping does not match these definitions, especially for long long values.
3. ctypes Type Mapping Table
ctypes type C type Python type
c_bool _Bool bool (1)
c_char char 1‑character bytes object
c_wchar wchar_t 1‑character string
c_byte char int
c_ubyte unsigned char int
c_short short int
c_ushort unsigned short int
c_int int int
c_uint unsigned int int
c_long long int
c_ulong unsigned long int
c_longlong __int64 or long long int
c_ulonglong unsigned __int64 or unsigned long long int
c_size_t size_t int
c_ssize_t ssize_t or Py_ssize_t int
c_float float float
c_double double float
c_longdouble long double float
c_char_p char * (NUL terminated) bytes object or None
c_wchar_p wchar_t * (NUL terminated) string or None
c_void_p void * int or None4. Handling Integer Return Values
Using the table, we map Go's long long to c_longlong and define a Structure with a single field.
from ctypes import *
import time
class StructPointer(Structure):
_fields_ = [("p", c_longlong,)]
if __name__ == '__main__':
begin = time.time()
s = CDLL("s1.so")
s.run.restype = StructPointer
result = s.run(100000000)
print("result:", result.p)
print("elapsed:", time.time() - begin)The output now matches the Go calculation.
5. Handling String Return Values
When a Go function returns a string, the generated header shows a struct _GoString_ containing a pointer and a length. We map it to a Structure with c_char_p and c_longlong.
class StrPointer(Structure):
_fields_ = [("p", c_char_p), ("n", c_longlong)]
s.speak.restype = StrPointer
speak = s.speak()
text = str(speak.p[:speak.n], encoding="utf-8")
print("speak:", text)The program prints the correct Chinese string returned from Go.
6. Conclusion
By correctly mapping C types to ctypes structures and setting restype, both integer and string return values from Go can be retrieved accurately in Python. This resolves the major interoperability pitfalls when using Python to call Go code.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Python Crawling & Data Mining
Life's short, I code in Python. This channel shares Python web crawling, data mining, analysis, processing, visualization, automated testing, DevOps, big data, AI, cloud computing, machine learning tools, resources, news, technical articles, tutorial videos and learning materials. Join us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
