Skip to content
Snippets Groups Projects
Commit 07bcd27e authored by David Hendriks's avatar David Hendriks
Browse files

working example of this idea is in ctypes_and_api

parent af4ca63c
No related branches found
No related tags found
No related merge requests found
Showing
with 305 additions and 55 deletions
No preview for this file type
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
typedef int (*fn_def)(void);
typedef double(*fn_def2)(double, double);
int test1()
{
// function to call
printf("Test\n");
}
double test2(double num1, double num2)
{
printf("%f %f", num1, num2);
}
void convert_and_call(void *fnvptr_val)
{
// convert into pointer
......@@ -16,26 +25,44 @@ void convert_and_call(void *fnvptr_val)
fnptr();
}
void convert_and_call2(void *fnvptr_val, double num1, double num2)
{
// convert into pointer
fn_def2 fnptr = (fn_def2)fnvptr_val;
fnptr(num1, num2);
}
int main()
{
void* fnvptr = (void*)&test1;
// // print adress
// printf("%p\n", &test1);
// print adress
printf("%p\n", &test1);
// printf("\n\nchar try\n");
// // To char
// // cast into char array
// char* a=(char*)fnvptr;
// cast into char array
char* a=(char*)fnvptr;
// // print stuff
// printf("%s\n", a);
// printf("size: %ld\n",sizeof(a));
// print stuff
printf("%s\n", a);
printf("size: %ld\n",sizeof(a));
// // cast into new void thing
// void * fnvptr2 = (void*)a;
// printf("%p\n", fnvptr2);
// cast into new void thing
void * fnvptr2 = (void*)a;
printf("%p\n", fnvptr2);
// // // convert into pointer
// convert_and_call(fnvptr2);
// // convert into pointer
convert_and_call(fnvptr2);
}
void* fnvptr3_old = (void*)&test2;
printf("%p size: %ld\n", fnvptr3_old, sizeof(fnvptr3_old));
char* fnvptr3_char=(char*)fnvptr3_old;
printf("%s has size %ld\n", fnvptr3_char, sizeof(fnvptr3_char));
void * fnvptr3_new = (void*)fnvptr3_char;
printf("%p\n", fnvptr3_new);
double numval_1 = 6.5;
double numval_2 = 5.0;
convert_and_call2(fnvptr3_new, numval_1, numval_2);
}
\ No newline at end of file
# Compile a shared library
gcc -shared -o libmean.so.1 -fPIC mean.c
gcc -o main -fPIC mean.c
\ No newline at end of file
# gcc -o main -fPIC mean.c
\ No newline at end of file
......@@ -21,31 +21,32 @@ def buildLibrary():
if not s==0:
print("return code:\n{}".format(s))
# Building library
buildLibrary()
def loadLibraryFunction():
# Building library
buildLibrary()
# Loading library
libmean = ctypes.CDLL("libmean.so.1") # loads the shared library
# Loading library
libmean = ctypes.CDLL("libmean.so.1") # loads the shared library
# #
# Pointer
print("Function pointer of the function printing the function pointer: {}".format(libmean.print_pointer_to_mean))
# Memory adress
libmean.print_pointer_to_mean()
# Get memory adress of function. mimicking a pointer
mem = ctypes.cast(libmean.mean, ctypes.c_void_p).value
# ijij
print("pointer to mean function (via python code): {}".format(mem))
print("Hex memory adress: {}".format(hex(mem)))
print(type(hex(mem)))
# #
# Pointer
# print("Function pointer of the function printing the function pointer: {}".format(libmean.print_pointer_to_mean))
# Memory adress
# libmean.print_pointer_to_mean()
# Get memory adress of function. mimicking a pointer
mem = ctypes.cast(libmean.mean, ctypes.c_void_p).value
# print some stuff
# print("pointer to mean function (via python code): {}".format(mem))
# print("Hex memory adress: {}".format(hex(mem)))
# print(type(hex(mem)))
return hex(mem)
hex_mem = loadLibraryFunction()
print(hex_mem)
# Other uses of this code
......
#include "mean.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double mean(double a, double b) {
printf("calculating mean with %f and %f", a, b);
......@@ -16,9 +17,4 @@ double calc_mean_using_pointer(double (*pf)(double, double), double number_1, do
result = pf(number_1, number_2);
printf("result running mean function with pointer to the function: %f", result);
return result;
}
void main() {
double res = double mean(double 3.1, double 6.2);
printf("result %f", res);
}
\ No newline at end of file
// Returns the mean of passed parameters
double mean(double, double);
void print_pointer_to_get_value();
double calc_mean_using_pointer(double (*pf)(double, double), double number_1, double number_2);
\ No newline at end of file
double calc_mean_using_pointer(double (*pf)(double, double), double number_1, double number_2);
File added
# Compile a shared library
gcc -shared -o libmean.so.1 -fPIC mean.c
# gcc -o main -fPIC mean.c
\ No newline at end of file
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "demolib.h"
typedef double (*fn_def)(double, double);
int add_number_using_pointer(int (*pf)(int, int), int number_1, int number_2) {
int result;
result = pf(number_1, number_2);
return result;
}
double calc_mean_using_pointer(long int str_1, double number_1, double number_2)
{
printf("test for running function with mem addr %ld with arguments %f %f\n", str_1, number_1, number_2);
// convert into pointer
fn_def fnptr = (fn_def)str_1;
printf("size of function pointer %zu\n",sizeof(fnptr));
printf("%p size: %zu\n", fnptr, sizeof(fnptr));
double result;
result = fnptr(number_1, number_2);
return result;
}
double test_func(char* str_1, double number_1, double number_2) {
// double result;
// result = pf(number_1, number_2);
printf("test for running function with mem addr %s with arguments %f %f\n", str_1, number_1, number_2);
return 6.5;
}
\ No newline at end of file
// Example header file
// char construct_string(int number);
double calc_mean_using_pointer(long int str_1, double number_1, double number_2);
double test_func(char* str_1, double number_1, double number_2);
\ No newline at end of file
// demomodule.c
#include <Python.h>
#include "demolib.h"
// https://stackoverflow.com/questions/51505391/how-to-parse-void-to-pyobject
static PyObject *DemoLib_CalcMeanWithPointerTest(PyObject *self, PyObject *args) {
char *str_1;
double number_1;
double number_2;
if (!PyArg_ParseTuple(args, "sdd", &str_1, &number_1, &number_2)) {
return NULL;
}
double result;
result = test_func(str_1, number_1, number_2);
return Py_BuildValue("d", result);
}
static PyObject *DemoLib_CalcMeanWithPointer(PyObject *self, PyObject *args) {
long int str_1;
double number_1;
double number_2;
if (!PyArg_ParseTuple(args, "ldd", &str_1, &number_1, &number_2)) {
return NULL;
}
double result;
printf("%p contents %ld\n", &str_1, str_1);
result = calc_mean_using_pointer(str_1, number_1, number_2);
return Py_BuildValue("d", result);
}
// module's function table
static PyMethodDef DemoLib_FunctionsTable[] = {
{
"calc_mean_with_pointer", // name exposed to Python
DemoLib_CalcMeanWithPointer, // C wrapper function
METH_VARARGS, // received variable args (but really just 1)
"Calculate the mean of two values via a pointer function" // documentation
},
{
"calc_mean_with_pointer_test", // name exposed to Python
DemoLib_CalcMeanWithPointerTest, // C wrapper function
METH_VARARGS, // received variable args (but really just 1)
"Calculate the mean of two values via a pointer function" // documentation
},
{
NULL, NULL, 0, NULL
}
};
// modules definition
static struct PyModuleDef DemoLib_Module = {
PyModuleDef_HEAD_INIT,
"demo", // name of module exposed to Python
"Demo Python wrapper for custom C extension library.", // module documentation
-1,
DemoLib_FunctionsTable
};
PyMODINIT_FUNC PyInit_demo(void) {
return PyModule_Create(&DemoLib_Module);
}
\ No newline at end of file
import ctypes
import os
import subprocess
def buildLibrary():
# store the return code of the c program(return 0)
# and display the output
s = subprocess.check_call("bash compile_shared_lib.sh", shell=True)
if not s==0:
print("return code:\n{}".format(s))
def loadLibraryFunction():
# OLD
# Building library
buildLibrary()
# Loading library
libmean = ctypes.CDLL("libmean.so.1") # loads the shared library
# #
# Pointer
# print("Function pointer of the function printing the function pointer: {}".format(libmean.print_pointer_to_mean))
# Memory adress
# libmean.print_pointer_to_mean()
# Get memory adress of function. mimicking a pointer
mem = ctypes.cast(libmean.mean, ctypes.c_void_p).value
# print some stuff
# print("pointer to mean function (via python code): {}".format(mem))
# print("Hex memory adress: {}".format(hex(mem)))
# print(type(hex(mem)))
# Other uses of this code
# print(libmean.mean)
# print(libmean.mean(ctypes.c_double(10), ctypes.c_double(3))) # call mean function needs cast arg types
# libmean.mean.argtypes = [ctypes.c_double, ctypes.c_double] # define arguments types
# print(libmean.mean(10, 3)) # call mean function does not need cast arg types
# print(type(libmean.mean(10, 5)))
return mem
\ No newline at end of file
File added
import ctypes
import os
import subprocess
from functions import loadLibraryFunction, buildLibrary
import demo
buildLibrary()
# Loading library
libmean = ctypes.CDLL("libmean.so.1") # loads the shared library
# Get memory adress of function. mimicking a pointer
mem = ctypes.cast(libmean.mean, ctypes.c_void_p).value
print("mem adress of mean function {}, type: {}".format(mem, type(mem)))
dong = demo.calc_mean_with_pointer(mem, 1.0, 2.0)
print(dong)
\ No newline at end of file
#include "mean.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double mean(double a, double b) {
printf("calculating mean with %f and %f", a, b);
return (a+b)/2;
}
void print_pointer_to_mean() {
printf("pointer to mean function (via c code): %p\n", &mean);
}
double calc_mean_using_pointer(double (*pf)(double, double), double number_1, double number_2) {
double result;
result = pf(number_1, number_2);
printf("result running mean function with pointer to the function: %f", result);
return result;
}
\ No newline at end of file
// Returns the mean of passed parameters
double mean(double, double);
void print_pointer_to_get_value();
double calc_mean_using_pointer(double (*pf)(double, double), double number_1, double number_2);
* Idea:
- In the main function we compile the functions mean.c and mean.h to a shared library, calling it libmean.so.1
- this library gets loaded into memory with ctypes.CDLL(<name lib>)
- the memory adress, and two floats get given to a c function that is bound with python through the python-c-api:
- these are defined in demolib.c
- these are connected with python using demomodule.c
- within that c function, the memory adress is made into the pointer to the function that is contained in the loaded shared library.
- This pointer is then called, with the two numbers and returns an output
* usage:
in this directory: pip install . --upgrade
then run python main.py
* Some leads:
# https://solarianprogrammer.com/2019/07/18/python-using-c-cpp-libraries-ctypes/
# https://gist.github.com/elyezer/7099291
# https://www.geeksforgeeks.org/turning-a-function-pointer-to-callable/
# https://stackoverflow.com/questions/9420673/is-it-possible-to-compile-c-code-using-python
# https://documentation.help/Python-3.2.1/ctypes.html
# https://stackoverflow.com/questions/49635105/ctypes-get-the-actual-address-of-a-c-function
# https://blog.regehr.org/archives/1621
# https://www.oreilly.com/library/view/understanding-and-using/9781449344535/ch01.html
\ No newline at end of file
from setuptools import Extension, setup
module = Extension("demo",
sources=[
'demolib.c',
'demomodule.c'
])
setup(name='demo',
version='1.0',
description='Python wrapper for custom C extension',
ext_modules=[module])
\ No newline at end of file
File deleted
......@@ -2,11 +2,6 @@
#include <stdlib.h>
#include "demolib.h"
int main(void) {
// Testing stuff for add_number function
int getal_1=2;
......@@ -53,15 +48,6 @@ int main(void) {
function_via_pointer_res_2 = add_number_using_pointer(pf3, 10, 20);
printf("result of calling a function with a function pointer to multiply_number: %d\n", function_via_pointer_res_2);
//
return(0);
}
\ No newline at end of file
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment