1

I'm experimenting with native C extensions in Python. What I'm trying to accomplish now is to pass Bytes buffer from Python to C.

I need to load a binary file from disk and pass that buffer to C extension however I have no clue what types should I use. What I have now is:

Python part:

import ctypes

lib = ctypes.cdll.LoadLibrary("lib.so")

f = open("file.png", "rb")
buf = f.read()
f.close()

lib.func(buf)

C part:

#include <stdio.h>

void func(int buf) {
    // do something with buf
}
1
  • 4
    Wait... your first attempt was int buf? It sounds like you might be in over your head trying to interface Python with C here - you might want to get more familiar with C on its own first. Commented Dec 31, 2020 at 12:09

3 Answers 3

1

Example solution passing binary data and length to C function which dumps it.

Python part:

import ctypes

lib = ctypes.cdll.LoadLibrary("./lib.so")
f = open("file.png", "rb")
buf = f.read()
f.close()

lib.func.argtypes = [ctypes.c_void_p, ctypes.c_uint]
lib.func(ctypes.cast(buf, ctypes.c_void_p), len(buf))

C part:

#include <stdio.h>

void func(unsigned char *buf, unsigned int len) {
    if (buf) {
        for (unsigned int i=0; i<len; i++) {
            if (i%16 == 0) {
                printf("\n");
            }
            printf("0x%02x ", buf[i]);
        }
        printf("\n");
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

Alternative solution:

import ctypes

p_data: bytes = b'\x01\x02\x03'
c_p_data_len = ctypes.c_uint(len(p_data))
c_p_data = (ctypes.c_ubyte * len(p_data))(*p_data)
dll_file = ctypes.CDLL("my_lib.dll")
result = dll_file.func(c_p_data, c_p_data_len)

Comments

0

Your C functions should be one of:

void func1(const char* buf, size_t len);  # for const data
void func2(char* buf, size_t len);        # for non-const data

And Python is:

import ctypes as ct

lib = ct.CDLL("./lib.so")
# While this case will work without it, always explicitly declare the argument types
# and return type to allow ctypes to type-check.  It will make assumptions otherwise.
lib.func1.argtypes = ct.c_char_p, ct.c_size_t
lib.func1.restype = None
lib.func2.argtypes = ct.c_char_p, ct.c_size_t
lib.func2.restype = None

with open("file.png", "rb") as f:
    buf1 = f.read()                           # for const data
    buf2 = ct.create_string_buffer(f.read())  # for non-const data

lib.func1(buf1, len(buf1))
lib.func2(buf2, len(buf2))

Note there is no protection for calling a non-const function with const data and you'll likely corrupt or crash Python. Make sure to pass writeable buffers to functions that edit the buffer in-place.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.