Hướng dẫn cffi python tutorial - hướng dẫn trăn cffi

Cách sử dụng mô-đun CFFI tích hợp Python, để giao tiếp với Python với các thư viện gốc như là một phương pháp thay thế cho phương pháp tiếp cận của CT CTYPES.

Hướng dẫn cffi python tutorial - hướng dẫn trăn cffi

Trong các hướng dẫn trước đây, chúng tôi đã đề cập đến những điều cơ bản của CTYPES và một số cách sử dụng CTYPES nâng cao. Hướng dẫn này sẽ bao gồm mô -đun

/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
5. CFFI là một môi trường phong phú hơn CTYPE, cho phép một số tùy chọn khác nhau cho cách bạn muốn giao tiếp với thư viện gốc.

Trong hướng dẫn này, chúng tôi sẽ đề cập:

  • Các giao diện trực tuyến ngoài dòng VS VS
  • Xây dựng và chạy tập lệnh dựa trên CFFI trên Linux
  • Tạo các lớp Python đơn giản để phản chiếu C
  • Vượt qua các cấu trúc bằng cách tham khảo
  • Làm việc xung quanh một số hạn chế CFFI

Như với các hướng dẫn trước đây, hãy để bắt đầu bằng cách xem xét thư viện C đơn giản mà chúng tôi sẽ sử dụng và cách xây dựng nó, sau đó nhảy vào tải thư viện C và gọi các chức năng trong đó.

Mã thư viện C

Tất cả các mã để xây dựng và kiểm tra các ví dụ được thảo luận ở đây (cũng như đánh dấu cho bài viết này) được cam kết với kho lưu trữ GitHub của tôi.

Thư viện bao gồm hai cấu trúc dữ liệu; Điểm và dòng. Một điểm là một cặp tọa độ (x, y) trong khi một đường có điểm bắt đầu và điểm cuối. Ngoài ra còn có một số ít các chức năng sửa đổi từng loại này.

Hãy cùng xem xét kỹ hơn về cấu trúc

/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
6 và các chức năng liên quan của nó.

/* Point.h */
/* Simple structure for ctypes example */
typedef struct {
    int x;
    int y;
} Point;

/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}

Tôi đã giành chiến thắng trong từng chức năng này một cách chi tiết vì chúng khá đơn giản. Bit thú vị duy nhất là sự khác biệt giữa

/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
7 và
/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
8. Chúng tôi sẽ nói một chút sau đó về các ngữ nghĩa qua từng giá trị và vượt qua.

Chúng tôi cũng sẽ sử dụng cấu trúc

/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
9, bao gồm hai điểm:

/* Line.h */
typedef struct {
    Point start;
    Point end;
} Line;

/* Line.c */
void show_line(Line line) {
    printf("Line in C      is (%d, %d)->(%d, %d)\n", line.start.x, line.start.y,
            line.end.x, line.end.y);
}

void move_line_by_ref(Line *line) {
    show_line(*line);
    move_point_by_ref(&line->start);
    move_point_by_ref(&line->end);
    show_line(*line);
}

Line get_line(void) {
    Line l = { get_default_point(), get_default_point() };
    return l;
}

Cấu trúc điểm và các chức năng liên quan của nó sẽ cho phép chúng tôi chỉ ra cách thiết lập và xây dựng ví dụ này và cách xử lý các tài liệu tham khảo bộ nhớ trong CTYPE. Cấu trúc dòng sẽ cho phép chúng ta làm việc với các cấu trúc lồng nhau và các biến chứng phát sinh từ đó.

Makefile trong repo được thiết lập để xây dựng hoàn toàn và chạy bản demo từ đầu:

all: point line

clean:
    rm -f *.o *.so *.html _point.c _line.c Line.h.preprocessed

libpoint.so: Point.o
    gcc -shared $^ -o $@

libline.so: Point.o Line.o
    gcc -shared $^ -o $@

%.o: %.c
    gcc -c -Wall -Werror -fpic $^

point: export LD_LIBRARY_PATH = $(shell pwd)
point: libpoint.so
    ./build_point.py
    ./testPoint.py

line: export LD_LIBRARY_PATH = $(shell pwd)
line: libline.so
    # hack to get around cffi not supporting #include directives
    gcc -E Line.h > Line.h.preprocessed
    ./build_line.py
    ./testLine.py

doc:
    pandoc ctypes2.md > ctypes2.html
    firefox ctypes2.html

Để xây dựng và chạy bản demo, bạn chỉ cần chạy lệnh sau trong vỏ của bạn:

Các giao diện trực tuyến ngoài dòng VS VS

Xây dựng và chạy tập lệnh dựa trên CFFI trên Linux

Tạo các lớp Python đơn giản để phản chiếu C

Vượt qua các cấu trúc bằng cách tham khảo

Làm việc xung quanh một số hạn chế CFFI

Như với các hướng dẫn trước đây, hãy để bắt đầu bằng cách xem xét thư viện C đơn giản mà chúng tôi sẽ sử dụng và cách xây dựng nó, sau đó nhảy vào tải thư viện C và gọi các chức năng trong đó.

Xây dựng và chạy tập lệnh dựa trên CFFI trên Linux

Tạo các lớp Python đơn giản để phản chiếu C

Vượt qua các cấu trúc bằng cách tham khảo

  • Làm việc xung quanh một số hạn chế CFFI
  • Như với các hướng dẫn trước đây, hãy để bắt đầu bằng cách xem xét thư viện C đơn giản mà chúng tôi sẽ sử dụng và cách xây dựng nó, sau đó nhảy vào tải thư viện C và gọi các chức năng trong đó.
  • Mã thư viện C
  • Tất cả các mã để xây dựng và kiểm tra các ví dụ được thảo luận ở đây (cũng như đánh dấu cho bài viết này) được cam kết với kho lưu trữ GitHub của tôi.

Thư viện bao gồm hai cấu trúc dữ liệu; Điểm và dòng. Một điểm là một cặp tọa độ (x, y) trong khi một đường có điểm bắt đầu và điểm cuối. Ngoài ra còn có một số ít các chức năng sửa đổi từng loại này.

point: export LD_LIBRARY_PATH = $(shell pwd)
point: libpoint.so
    ./build_point.py
    ./testPoint.py

Hãy cùng xem xét kỹ hơn về cấu trúc

/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
6 và các chức năng liên quan của nó.

Tôi đã giành chiến thắng trong từng chức năng này một cách chi tiết vì chúng khá đơn giản. Bit thú vị duy nhất là sự khác biệt giữa

/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
7 và
/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
8. Chúng tôi sẽ nói một chút sau đó về các ngữ nghĩa qua từng giá trị và vượt qua.

Chúng tôi cũng sẽ sử dụng cấu trúc

/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
9, bao gồm hai điểm:

Cấu trúc điểm và các chức năng liên quan của nó sẽ cho phép chúng tôi chỉ ra cách thiết lập và xây dựng ví dụ này và cách xử lý các tài liệu tham khảo bộ nhớ trong CTYPE. Cấu trúc dòng sẽ cho phép chúng ta làm việc với các cấu trúc lồng nhau và các biến chứng phát sinh từ đó.

Makefile trong repo được thiết lập để xây dựng hoàn toàn và chạy bản demo từ đầu:

Để xây dựng và chạy bản demo, bạn chỉ cần chạy lệnh sau trong vỏ của bạn:

Mã đó trông như thế này:

ffi = cffi.FFI()

with open(os.path.join(os.path.dirname(__file__), "Point.h")) as f:
    ffi.cdef(f.read())

ffi.set_source("_point",
    '#include "Point.h"',
    libraries=["point"],
    library_dirs=[os.path.dirname(__file__),],
)

ffi.compile()

Mã này đọc trong tệp tiêu đề và chuyển nó đến mô -đun FFI CFFI sang phân tích cú pháp. (Lưu ý: FFI là một thư viện trên đó được viết CFFI)

Khi FFI có thông tin tiêu đề, sau đó chúng tôi đặt thông tin nguồn. Tham số đầu tiên cho hàm set_source là tên của tệp .c bạn muốn nó tạo. Tiếp theo là nguồn C tùy chỉnh bạn muốn chèn. Trong trường hợp của chúng tôi, mã tùy chỉnh này chỉ đơn giản là bao gồm tệp point.h từ thư viện mà chúng tôi đang nói chuyện. Cuối cùng, bạn cần cho nó biết một số thông tin về thư viện bạn muốn nó liên kết với.

Sau khi chúng tôi đọc và xử lý các tiêu đề và thiết lập tệp nguồn, chúng tôi bảo CFFI gọi trình biên dịch và xây dựng mô -đun giao diện. Trên hệ thống của tôi, bước này tạo ra ba tệp:

_point.c
_point.o
_point.cpython-35m-x86_64-linux-gnu.so

Tệp _point.c dài hơn 700 dòng và giống như hầu hết các mã được tạo, có thể khó đọc. Tệp .o là đầu ra từ trình biên dịch và tệp .so là mô -đun giao diện chúng tôi muốn.

Bây giờ chúng tôi đã có mô -đun giao diện, chúng tôi có thể tiếp tục và viết một số Python để nói chuyện với thư viện C của chúng tôi!

Tạo các lớp Python đơn giản để phản chiếu C

Chúng ta có thể xây dựng một lớp Python đơn giản để bao quanh cấu trúc C mà chúng ta sử dụng trong thư viện này. Giống như các hướng dẫn CTYPES của chúng tôi, điều này khá đơn giản vì CFFI thực hiện dữ liệu cho chúng tôi. Để sử dụng mã được tạo, trước tiên chúng tôi phải nhập mô -đun mà CFFI đã tạo cho chúng tôi:

Sau đó, chúng tôi xác định lớp của chúng tôi, phương thức

/* Line.h */
typedef struct {
    Point start;
    Point end;
} Line;
1 trong đó chỉ cần gọi thư viện C để lấy cho chúng tôi một đối tượng điểm:

class Point():
    def __init__(self, x=None, y=None):
        if x:
            self.p = _point.lib.get_point(x, y)
        else:
            self.p = _point.lib.get_default_point()

Bạn có thể thấy rằng thư viện CFFI cho phép chúng tôi truy cập trực tiếp các chức năng trong thư viện C và cho phép chúng tôi lưu trữ

/* Line.h */
typedef struct {
    Point start;
    Point end;
} Line;
2 được trả về. Nếu bạn thêm một dòng
/* Line.h */
typedef struct {
    Point start;
    Point end;
} Line;
3 vào cuối hàm init, bạn sẽ thấy rằng nó lưu trữ nó trong một đối tượng CDATA có tên:init function, you’ll see that it stores this in a named cdata object:


Tuy nhiên,

/* Line.h */
typedef struct {
    Point start;
    Point end;
} Line;
4 đó vẫn có các thành viên dữ liệu X và Y, do đó bạn có thể nhận và đặt các giá trị đó khá dễ dàng, như bạn có thể thấy trong hàm repr cho lớp của chúng tôi:repr function for our class:

/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
0

Chúng tôi cũng có thể dễ dàng kết thúc các phương thức

/* Line.h */
typedef struct {
    Point start;
    Point end;
} Line;
5 và
/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
7 trong thư viện của chúng tôi trong các phương thức lớp học:

/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
1

Vượt qua các cấu trúc bằng cách tham khảo

Khi chúng ta vượt qua các giá trị bằng cách tham chiếu trong hàm

/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
8, chúng ta cần thực hiện một công việc làm thêm một chút để giúp CFFI tạo một đối tượng để nó có thể lấy địa chỉ của nó và vượt qua điều đó. Điều này đòi hỏi một mã nhỏ, nhưng không nhiều. Nguyên mẫu cho hàm C mà chúng tôi đang cố gắng gọi là:

/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
2

Để gọi như vậy, chúng ta cần gọi hàm ffi.new () với hai tham số. Đầu tiên là một chuỗi chỉ ra loại đối tượng được tạo. Loại này phải phù hợp với một loại đã biết của người Viking trong trường hợp FFI đó. Trong trường hợp của chúng tôi, nó biết về loại

/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
6 vì cuộc gọi đến CFFI.CDEF mà chúng tôi đã làm trong quá trình xử lý ngoại tuyến. Tham số thứ hai cho ffi.new () là giá trị ban đầu cho đối tượng. Trong trường hợp này, chúng tôi muốn đối tượng được tạo bắt đầu với điểm tự.p của chúng tôi.

/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
3

Chúng tôi kết thúc bằng cách sao chép giá trị mới từ điểm* trở lại thành viên CDATA tự.p của chúng tôi.

Bộ nhớ được tạo bởi ffi.new () sẽ được thu thập cho chúng tôi trừ khi chúng tôi cần làm điều gì đó đặc biệt với nó (xem hàm ffi.gc () nếu bạn cần điều đó).

Làm việc xung quanh một số hạn chế CFFI

Chúng tôi cũng có một cấu trúc dòng, giữ hai điểm. Cấu trúc này, trong khi khá đơn giản, cho thấy một giới hạn trong CFFI mà rất đáng để thảo luận. Trong tập lệnh xử lý ngoại tuyến cho thư viện điểm, build_point.py, chúng tôi chỉ cần đọc trực tiếp tệp tiêu đề điểm.h và trao nó cho cffi.cdef (). Mô hình này bị phá vỡ khi chúng ta truy cập tập lệnh build_line.py do giới hạn của CFFI. CFFI, vì một số lý do khá chính đáng, tôi đã giành chiến thắng ở đây, không cho phép các chỉ thị tiền xử lý (tức là các dòng bắt đầu bằng #đấm). Điều này ngăn chúng ta vượt qua dòng nó.h trực tiếp như dòng đầu tiên là:

Có một vài giải pháp phổ biến mà tôi đã thấy trong khi nghiên cứu hướng dẫn này. Một là tùy chỉnh viết thông tin tiêu đề C, có thể trực tiếp vào tệp build_line.py. Một cái khác, mà tôi nghĩ tôn trọng nguyên tắc khô, là sử dụng bộ tiền xử lý C để tạo tệp chúng tôi đọc. Điều này hiển thị trong Makefile như:

/* Point.c */
/* display a Point value */
void show_point(Point point) {
    printf("Point in C      is (%d, %d)\n", point.x, point.y);
}

/* Increment a Point which was passed by value */
void move_point(Point point) {
    show_point(point);
    point.x++;
    point.y++;
    show_point(point);
}

/* Increment a Point which was passed by reference */
void move_point_by_ref(Point *point) {
    show_point(*point);
    point->x++;
    point->y++;
    show_point(*point);
}

/* Return by value */
Point get_default_point(void) {
    static int x_counter = 0;
    static int y_counter = 100;
    x_counter++;
    y_counter--;
    return get_point(x_counter, y_counter);
}

Point get_point(int x, int y) {
    Point point = { x, y };
    printf("Returning Point    (%d, %d)\n", point.x, point.y);
    return point;
}
4

Dòng

/* Line.h */
typedef struct {
    Point start;
    Point end;
} Line;
9 chạy bộ tiền xử lý trên dòng.H và chúng tôi lưu trữ đầu ra trong dòng.h.preproced. Trong tập lệnh build_line.py, thay vì đọc từ line.h, chúng tôi đã đọc line.h.preproced và chuyển nó cho chức năng cffi.cdef () thay thế.

Lưu ý: Thủ thuật này sẽ không phải lúc nào cũng hoạt động, có nhiều trường hợp các phần mở rộng dành riêng cho trình biên dịch được sử dụng trong các tiêu đề tiêu chuẩn (như Std Stdio.h,) sẽ khiến CFFI bị lỗi. This trick will not always work, there are many cases where compiler-specific extensions are used in the standard headers (like “stdio.h”) which will cause cffi to fail.

Phần còn lại của ví dụ dòng theo các khái niệm chúng ta đã học trong mã điểm trên.

Sự kết luận

Trong hướng dẫn này, chúng tôi đã đề cập đến một số điều cơ bản về mô -đun CFFI và cách sử dụng nó để giao diện các thư viện C gốc.Tôi tìm thấy một số tài nguyên ngoài kia trong khi nghiên cứu.Ví dụ python-cffi là một ví dụ đầy đủ về mã sử dụng CFFI.Nó tạo ra các nguyên mẫu chức năng tùy chỉnh thay vì gọi bộ tiền xử lý như chúng tôi đã làm trong phần cuối.

Nếu bạn quan tâm đến việc chuyển các con trỏ qua giao diện CFFI, bạn nên bắt đầu bằng cách đọc phần này của tài liệu này một cách cẩn thận.Tôi thấy nó khá đáng giá.

Nếu bạn sắp chết để đọc thêm về lý do tại sao các chỉ thị tiền xử lý C không được hỗ trợ, tôi sẽ khuyên bạn nên bắt đầu với chủ đề này.Các mô tả ở đó bao gồm các vấn đề trong một số chi tiết.

Và cuối cùng, nếu bạn muốn xem và chơi với mã tôi đã viết khi làm việc này, vui lòng truy cập kho lưu trữ GitHub của tôi.Hướng dẫn này nằm trong thư mục ‘CFFI.