- Learning Cython Programming(Second Edition)
- Philip Herron
- 832字
- 2021-07-16 09:45:26
Cython keyword – cdef
The cdef
keyword tells the compiler that this statement is a native C type or native function. Remember from Chapter 1, Cython Won't Bite that we used this line to declare the C prototype function:
cdef int AddFunction(int, int)
This is the line that let us wrap the native C function into a Python callable using the Python def
keyword. We can use this in many contexts, for example, we can declare normal variables for use within a function to speed up execution:
def square(int x): return x ** 2
This is a trivial example, but it will tell the compiler that we will always be squaring an integer. However, for normal Python code, it's a little more complicated as Python has to worry a lot more about losing precision when it comes to handling many different types. But in this case, we know exactly what the type is and how it can be handled.
You might also have noticed that this is a simple def
function, but because it will be fed to the Cython compiler, this will work just fine, and handle the typed parameter as you would expect.
Structs
C structs can be worked with directly in Cython. For example, this header declares a simple struct
:
#ifndef __MYCODE_H__ #define __MYCODE_H__ struct mystruct { char * string; int integer; char ** string_array; }; extern void printStruct (struct mystruct *); #endif //__MYCODE_H__
This random struct
will demonstrate several concepts, including working with an array. Firstly, we must declare the layout of the struct
inside Cython. We can again use the cdef
block syntax. Everything within that block is a cdef
and will include the specified header, which is important when the output from the Cython compiler is compiled via GCC or Clang:
cdef extern from "mycode.h": struct mystruct: char * string int integer char ** string_array void printStruct (mystruct *)
Now that we have declared the prototype printStruct
function, we can use this to verify the data outside of Cython's scope. To work with this raw data type, we will make a testStruct
Python callable, which we will invoke using a simple Python import:
def testStruct (): cdef mystruct s cdef char *array [2] s.string = "Hello World" s.integer = 2 array [0] = "foo" array [1] = "bar" s.string_array = array printStruct (&s)
Let's look at this more closely. We firstly declare an instance of the struct
on the stack. Next, we declare a C-String array of size 2. The next lines will look familiar via setting each of the members of the struct
with a value. But notice that we declared our string array on the stack and then set the string array member to this instance. This is important as Cython will rely on the programmer to understand memory and stack versus heap properly. But it's important to notice that passing strings from language to language is completely trivial.
The final caveat with structs is while defining a cdef
declaration for a function. If a parameter is a struct, you never declare it as follows:
void myfunc (struct mystruct * x)
Instead, we simply use the following:
void myfunc (mystruct * x)
Cython will figure it out.
There are a few subtleties with the testStruct
function. In Cython, we have the reference operator '&
' that works just as in C. Therefore, with this struct
on the stack, we can pass a pointer via the reference operator just like in C.
Note that we don't have a '→
' operator in Cython. When accessing members inside the struct
(even if it is a pointer), we simply use the '.
' operator. Cython understands the context and will handle it.
From the previous example and for the sake of completeness we can implement the printStruct
function simply as:
#include <stdio.h> #include "mycode.h" void printStruct (struct mystruct * s) { printf(".string = %s\n", s->string); printf(".integer = %i\n", s->integer); printf(".string_array = \n"); int i; for (i = 0; i < s->integer; ++i) printf ("\t[%i] = %s\n", i, s->string_array [i]); }
This demonstrates even when we initialize the C struct from within Cython code it's a perfectly valid C type. A simple run of this in the downloaded code is as follows:
$ cd chapter2/cpy-cdef-reference $ make $ python >>> from mycodepy import testStruct >>> testStruct () .string = Hello World .integer = 2 .string_array = [0] = foo [1] = bar
This demonstrates that Cython can work with C structs—it initialized the C struct and assigned its data members, as you would expect if it was from C.
Enums
Interfacing with C enums is simple. If you have the following enum in C:
enum cardsuit { CLUBS, DIAMONDS, HEARTS, SPADES };
Then this can be expressed as the following Cython declaration:
cdef enum cardsuit: CLUBS, DIAMONDS, HEARTS, SPADES
Then, use the following as the cdef
declaration within our code:
cdef cardsuit card = CLUBS
It's a very small example, but it's important to see how simple it is.
- Learning LibGDX Game Development(Second Edition)
- TensorFlow Lite移動端深度學習
- WSO2 Developer’s Guide
- Visual C++數字圖像處理技術詳解
- INSTANT Sinatra Starter
- OpenGL Data Visualization Cookbook
- Mastering Linux Security and Hardening
- Processing創意編程指南
- Java設計模式深入研究
- Mastering ArcGIS Server Development with JavaScript
- Java 7 Concurrency Cookbook
- LabVIEW數據采集(第2版)
- Game Development Patterns and Best Practices
- 軟件定義存儲:原理、實踐與生態
- C/C++程序設計教程:面向過程分冊