Integração entre Python e C++: Passagem de Tipos Primitivos, Strings e Matrizes com ctypes

A biblioteca ctypes do Python permite a chamada de funções em bibliotecas compartilhadas (DLLs no Windows ou arquivos .so no Linux) escritas em C ou C++. Para garantir a interoperabilidade, é necessário mapear corretamente os tipos de dados entre as linguagens.

Mapeamento de Tipos: ctypes vs C

Tipo ctypes Tipo C Tipo Python
c_bool _Bool bool
c_char char string (1 caractere)
c_byte char int
c_ubyte unsigned char int
c_short short int
c_int int int
c_uint unsigned int int
c_long long int
c_float float float
c_double double float
c_char_p char * string ou None
c_void_p void * int ou None

Implementação em C++

Para que as funções C++ sejam acessíveis via ctypes, elas devem ser expostas usando extern "C" para evitar a alteração de nomes (name mangling) pelo compilador C++.


#include <iostream>
#include <vector>

// Arquivo: biblioteca.cpp
// Compilação Linux: g++ -o biblioteca.so -shared -fPIC biblioteca.cpp
// Compilação Windows: g++ -o biblioteca.dll -shared biblioteca.cpp

extern "C" {
    int processar_dados(int valor_int, char letra, const char* texto, int vetor_int[4], char matriz_char[2][2]) {
        std::cout << "Integro recebido: " << valor_int << std::endl;
        std::cout << "Caractere recebido: " << letra << std::endl;
        std::cout << "String recebida: " << texto << std::endl;

        std::cout << "Array unidimensional: ";
        for(int i = 0; i < 4; i++) {
            std::cout << vetor_int[i] << " ";
        }
        std::cout << std::endl;

        std::cout << "Matriz bidimensional:" << std::endl;
        for(int i = 0; i < 2; i++) {
            for(int j = 0; j < 2; j++) {
                std::cout << "[" << matriz_char[i][j] << "] ";
            }
            std::cout << std::endl;
        }

        return 1;
    }
}

Implementação em Python

No lado do Python, utilizamos a classe CDLL para carrgear a biblioteca e definimos as estruturas de dados necessárias para matrizes e ponteiros.


import ctypes
import os

# Carregar a biblioteca compartilhada
lib_path = os.path.abspath("biblioteca.so")
lib = ctypes.CDLL(lib_path)

# Preparação de strings (UTF-8 para compatibilidade)
string_input = "Texto de exemplo".encode('utf-8')

# Definição e inicialização de um array unidimensional (4 inteiros)
TipoArrayInt4 = ctypes.c_int * 4
meu_vetor = TipoArrayInt4(10, 20, 30, 40)

# Definição e inicialização de uma matriz 2x2 de caracteres
TipoLinhaChar2 = ctypes.c_char * 2
TipoMatrizChar2x2 = TipoLinhaChar2 * 2
minha_matriz = TipoMatrizChar2x2()

minha_matriz[0][0] = b'W'
minha_matriz[0][1] = b'X'
minha_matriz[1][0] = b'Y'
minha_matriz[1][1] = b'Z'

# Chamada da função C++
# Protótipo: int processar_dados(int, char, char*, int[4], char[2][2])
resultado = lib.processar_dados(
    ctypes.c_int(500),
    ctypes.c_char(b'R'),
    ctypes.c_char_p(string_input),
    meu_vetor,
    minha_matriz
)

print(f"Execução finalizada com status: {resultado}")

Considerações sobre Matrizes Multidimensionais

Ao lidar com matrizes multidimensionais no ctypes, a estrutura é criada multilpicando o tipo base pelo número de colunas e, em seguida, multiplicando o resultado pelo número de linhas. Isso garante que a disposição na memória seja contígua, exatamente como esperado por um compilador C/C++.

Tags: Python cpp ctypes interoperability DLL

Publicado em 7-14 11:40