Hướng dẫn libc python - con trăn libc

Ta thường sử dụng C/C++ cho những công việc yêu cầu tốc độ xử lý cũng như hiệu năng cao. Vậy làm thế nào để ta có thể gọi các hàm được cung cấp trong các thư viện C từ Python? Bài viết này trả lời câu hỏi trên.

Python cung cấp module ctypes để ta có thể giao tiếp với các thư viện ngoài của C.

Load thư viện động

Để load một thư viện động, ta sử dụng hàm cdll.LoadLibrary() từ module ctypes. Đoạn code dưới đây sẽ import bộ thư viện chuẩn glibc của C trong GNU/Linux:

import ctypes as ct

libc = ct.cdll.LoadLibrary('libc.so.6')

# Or we can use CDLL
libc = ct.CDLL('libc.so.6')

Gọi hàm

Sau khi đã load được thư viện, ta có thể gọi hàm C như những hàm Python bình thường. Dưới đây ta gọi hàm

libc.printf(b"Hello world! %d %s\n", 5, b"whoami")
# Hello world! 5 whomai

print(libc.time(None))
# 1150945864
1 và
libc.printf(b"Hello world! %d %s\n", 5, b"whoami")
# Hello world! 5 whomai

print(libc.time(None))
# 1150945864
2 của C, lưu ý rằng
libc.printf(b"Hello world! %d %s\n", 5, b"whoami")
# Hello world! 5 whomai

print(libc.time(None))
# 1150945864
3 pointer trong C tương ứng với
libc.printf(b"Hello world! %d %s\n", 5, b"whoami")
# Hello world! 5 whomai

print(libc.time(None))
# 1150945864
4 trong Python:

libc.printf(b"Hello world! %d %s\n", 5, b"whoami")
# Hello world! 5 whomai

print(libc.time(None))
# 1150945864

None, integers, bytes objects và (unicode) strings là các kiểu dữ liệu căn bản của Python và có thể được truyền trực tiếp như là đối số khi gọi hàm C.

None tương ứng với NULL pointer, bytes objects và strings được sử dụng như là con trỏ tới vùng nhớ chứa dữ liệu của nó (

libc.printf(b"Hello world! %d %s\n", 5, b"whoami")
# Hello world! 5 whomai

print(libc.time(None))
# 1150945864
5 hoặc
libc.printf(b"Hello world! %d %s\n", 5, b"whoami")
# Hello world! 5 whomai

print(libc.time(None))
# 1150945864
6). Trong ví dụ trên, ta sử dụng bytes object (b"Hello world! %d %s\n") như là con trỏ
libc.printf(b"Hello world! %d %s\n", 5, b"whoami")
# Hello world! 5 whomai

print(libc.time(None))
# 1150945864
5 khi gọi hàm
libc.printf(b"Hello world! %d %s\n", 5, b"whoami")
# Hello world! 5 whomai

print(libc.time(None))
# 1150945864
8. Kiểu integers của Python sẽ được sử dụng như
libc.printf(b"Hello world! %d %s\n", 5, b"whoami")
# Hello world! 5 whomai

print(libc.time(None))
# 1150945864
9 của C.

Dưới đây ta sẽ tìm hiểu rõ hơn về các kiểu dữ liệu mà ctypes hỗ trợ.

Các kiểu dữ liệu cơ bản

ctypes định nghĩa một số kiểu dữ liệu tương ứng với các kiểu dữ liệu cơ bản của C:

Hướng dẫn libc python - con trăn libc

Tất cả các kiểu này có thể được khởi tạo như sau:

>>> c_int()
c_long(0)
>>> c_wchar_p("Hello, World")
c_wchar_p('Hello, World')
>>> c_ushort(-3)
c_ushort(65533)

Và có thể thày đổi gía trị của nó:

>>> i = c_int(42)
>>> print(i)
c_long(42)
>>> print(i.value)
42
>>> i.value = -99
>>> print(i.value)
-99

Truyền con trỏ trong Python

Nhiều hàm trong C yêu cầu đối số truyền vào là một con trỏ, vì vậy ctypes cung cấp cho cho chúng ta hàm

>>> c_int()
c_long(0)
>>> c_wchar_p("Hello, World")
c_wchar_p('Hello, World')
>>> c_ushort(-3)
c_ushort(65533)

0. Gỉa sử ta có hàm hoán đổi gía trị của 2 số nguyên trong thư viện
>>> c_int()
c_long(0)
>>> c_wchar_p("Hello, World")
c_wchar_p('Hello, World')
>>> c_ushort(-3)
c_ushort(65533)

1:

void swap(int *a, int *b);

Làm thế nào để ta có thể gọi hàm đấy trong Python?

from ctypes import *

lib = cdll.LoadLibrary('/home/vuong/swap.so')

a = c_int(5)
b = c_int(13)
lib.swap(byref(a), byref(b))

Khai báo Structs và Unions

Để khai báo structures và unions, ta kế thừa 2 class tương ứng trong ctypes là

>>> c_int()
c_long(0)
>>> c_wchar_p("Hello, World")
c_wchar_p('Hello, World')
>>> c_ushort(-3)
c_ushort(65533)

2 và
>>> c_int()
c_long(0)
>>> c_wchar_p("Hello, World")
c_wchar_p('Hello, World')
>>> c_ushort(-3)
c_ushort(65533)

3. Mỗi subclass phải định nghĩa một thuộc tính
>>> c_int()
c_long(0)
>>> c_wchar_p("Hello, World")
c_wchar_p('Hello, World')
>>> c_ushort(-3)
c_ushort(65533)

4, là một list các 2-tuples (gồm 2 trường name và type).

Gỉa sử ta có khai báo struct và union trong C:


struct UserInfo {
    char name[50];
    int age;
    float height;
};

union UTag {
    int ival;
    float fval;
    char *sval;
};

Ta có đoạn code tương ứng trong Python, sử dụng class Structure và Union:

from ctypes import *

class UserInfo(Structure):
    _fields_ = [
        ('name', c_char * 50), # array of 50 characters
        ('age', c_int),
        ('height', c_float)
    ]

class UTag(Union):
    _fields_ = [
        ('ival', c_int),
        ('fval', c_float),
        ('sval', c_char_p)
    ]

Đoạn code trên cũng minh họa khai báo mảng trong python.

Happy coding!