Obsah
2. Krátké zopakování: nativní (céčková) knihovna pro výpočet a vykreslení fraktálů
3. Interaktivní části aplikace naprogramovaná v Pythonu
4. Céčkovská struktura obsahující ukazatel
5. Céčkovské funkce akceptující strukturu obsahující ukazatel
6. Volání upravených nativních funkcí z Pythonu s předáním struktury s ukazateli
8. Úplný zdrojový kód Pythonní části demonstračního příkladu
9. Korektní varianta předávání struktury obsahující ukazatel
10. Poslední varianta demonstračního příkladu: nativní i Pythonní část
11. Bitová pole v jazyku C a Pythonu
12. Předání běžné struktury (nikoli bitového pole) hodnotou a odkazem
13. Definice bitového pole v jazyku C
14. Definice struktury v Pythonu bez ohledu na bitové šířky prvků
15. Definice struktury v Pythonu s ohledem na bitové šířky prvků
16. Korektní způsob předání bitového pole z Pythonu do nativní funkce
17. Zarovnání prvků ve strukturách
18. Repositář s demonstračními příklady
1. Propojení Pythonu s nativními knihovnami s využitím balíčku ctypes: zarovnání ve strukturách, bitová pole
V předchozím článku o volání nativních funkcí z Pythonu přes knihovnu ctypes jsme se zabývali způsobem předávání struktur (struct) a ukazatelů (pointer) z jazyka Python do céčka (včetně kombinace obou způsobů, tj. předání ukazatele na strukturu). Dnes na toto téma navážeme. Zabývat se budeme trojicí problémů: předáváním struktur, které obsahují jako své prvky ukazatele, předáváním bitových polí a taktéž problematikou zarovnání prvků ve strukturách. Se všemi těmito problémy se pochopitelně velmi často můžeme setkat v praxi.
2. Krátké zopakování: nativní (céčková) knihovna pro výpočet a vykreslení fraktálů
Připomeňme si hlavní téma předchozího článku. Ukázali jsme si v něm, jakým způsobem je možné předávat datové struktury z Pythonu do nativních funkcí naprogramovaných v jazyku C. Jedná se (z pohledu jazyka C) o běžné struktury (struct) předávané buď hodnotou nebo odkazem, tedy přes ukazatel.
Konkrétně se jednalo o tyto dvě jednoduché struktury:
typedef struct {
unsigned int width;
unsigned int height;
} image_size_t;
typedef struct {
unsigned int maxiter;
double cx;
double cy;
} rendering_params_t;
Tyto struktury jsou použity pro předání parametrů do nativních (céčkovských) funkcí nazvaných render_mandelbrot a render_julia:
#include "renderer.h"
void putpixel(unsigned char **pixel, const unsigned char *palette,
int color_index) {
int color_offset = color_index * 3;
unsigned char *pal = (unsigned char *)(palette + color_offset);
*(*pixel)++ = *pal++;
*(*pixel)++ = *pal++;
*(*pixel)++ = *pal;
(*pixel)++;
}
void render_mandelbrot(image_size_t *image_size,
const unsigned char *palette, unsigned char *pixels,
rendering_params_t *rendering_params) {
int x, y;
double cx, cy;
double xmin = -2.0, ymin = -1.5, xmax = 1.0, ymax = 1.5;
unsigned char *p = pixels;
cy = ymin;
for (y = 0; y < image_size->height; y++) {
cx = xmin;
for (x = 0; x < image_size->width; x++) {
double zx = 0.0;
double zy = 0.0;
unsigned int i = 0;
while (i < rendering_params->maxiter) {
double zx2 = zx * zx;
double zy2 = zy * zy;
if (zx2 + zy2 > 4.0) {
break;
}
zy = 2.0 * zx * zy + cy;
zx = zx2 - zy2 + cx;
i++;
}
putpixel(&p, palette, i);
cx += (xmax - xmin) / image_size->width;
}
cy += (ymax - ymin) / image_size->height;
}
}
void render_julia(image_size_t *image_size,
const unsigned char *palette, unsigned char *pixels,
rendering_params_t *rendering_params) {
int x, y;
double zx0, zy0;
double xmin = -1.5, ymin = -1.5, xmax = 1.5, ymax = 1.5;
unsigned char *p = pixels;
zy0 = ymin;
for (y = 0; y < image_size->height; y++) {
zx0 = xmin;
for (x = 0; x < image_size->width; x++) {
double zx = zx0;
double zy = zy0;
unsigned int i = 0;
while (i < rendering_params->maxiter) {
double zx2 = zx * zx;
double zy2 = zy * zy;
if (zx2 + zy2 > 4.0) {
break;
}
zy = 2.0 * zx * zy + rendering_params->cy;
zx = zx2 - zy2 + rendering_params->cx;
i++;
}
putpixel(&p, palette, i);
zx0 += (xmax - xmin) / image_size->width;
}
zy0 += (ymax - ymin) / image_size->height;
}
}
3. Interaktivní části aplikace naprogramovaná v Pythonu
Opět si pro zopakování ukažme, jak vypadá interaktivní část aplikace, která je naprogramovaná v Pythonu a která volá nativní funkce render_mandelbrot a render_julia. Těmto funkcím jsou pochopitelně předány všechny potřebné parametry, včetně dvou struktur (dokonce referencí, nikoli hodnotou):
import sys
from ctypes import (
CDLL,
c_double,
c_int,
c_uint,
create_string_buffer,
Structure,
pointer,
)
from palette_mandmap import palette
import pygame
import pygame.locals
TITLE = "Renderer"
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 300
IMAGE_WIDTH = 256
IMAGE_HEIGHT = 256
MAXITER = 150
def initialize_ui(title, width, height):
"""Initialize Pygame display, drawing surface, and clocks."""
# set window title
pygame.display.set_caption(title)
# initialize window
display = pygame.display.set_mode([width, height])
display.fill((0, 0, 0))
clock = pygame.time.Clock()
return display, clock
def palette_to_buffer(p):
s = create_string_buffer(len(p) * 3)
i = 0
for color in p:
s[i] = color[0]
s[i + 1] = color[1]
s[i + 2] = color[2]
i += 3
return s
def event_loop(display, image1, image2, clock):
while True:
for event in pygame.event.get():
if event.type == pygame.locals.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.locals.KEYDOWN:
if event.key == pygame.locals.K_ESCAPE:
pygame.quit()
sys.exit()
# all events has been processed - update scene and redraw the screen
display.blit(image1, (30, 20))
display.blit(image2, (60 + image1.get_width(), 20))
# and update the whole display
pygame.display.update()
clock.tick(25)
def image_from_buffer(buffer, width, height, fmt):
return pygame.image.frombytes(bytes(buffer), (width, height), fmt)
class ImageSize(Structure):
_fields_ = [("width", c_uint), ("height", c_uint)]
class RenderingParams(Structure):
_fields_ = [("maxiter", c_uint), ("cx", c_double), ("cy", c_double)]
def main():
image_size = ImageSize(IMAGE_WIDTH, IMAGE_HEIGHT)
cx = -0.171119200000000013445
cy = 0.657309400000000000000
rendering_params = RenderingParams(MAXITER, cx, cy)
pal = palette_to_buffer(palette)
display, clock = initialize_ui(TITLE, SCREEN_WIDTH, SCREEN_HEIGHT)
# try to load dynamically linked library
renderer = CDLL("./renderer.so")
# create buffer for raster image
buffer = create_string_buffer(4 * IMAGE_WIDTH * IMAGE_HEIGHT)
# render Mandelbrot set into buffer
renderer.render_mandelbrot(
pointer(image_size), pal, buffer, pointer(rendering_params)
)
image1 = image_from_buffer(buffer, IMAGE_WIDTH, IMAGE_HEIGHT, "RGBX")
# render Julia set into buffer
renderer.render_julia(pointer(image_size), pal, buffer, pointer(rendering_params))
image2 = image_from_buffer(buffer, IMAGE_WIDTH, IMAGE_HEIGHT, "RGBX")
event_loop(display, image1, image2, clock)
if __name__ == "__main__":
main()
# finito
4. Céčkovská struktura obsahující ukazatel
V předchozím demonstračním příkladu se do céčkových funkcí ve skutečnosti samostatně předávaly dvě informace související s obrázkem – struktura s jeho rozměry a v dalším samostatném parametru ukazatel na buffer s pixely:
void render_mandelbrot(image_size_t *image_size,
const unsigned char *palette, unsigned char *pixels,
rendering_params_t *rendering_params) {
Možná by mohlo být výhodnější tyto informace spojit do jediné struktury, která by mohla vypadat následovně:
typedef struct {
unsigned int width;
unsigned int height;
unsigned char *pixels;
} image_t;
Druhá datová struktura, kterou používáme a která obsahuje informace o fraktálu, zůstane stále stejná:
typedef struct {
unsigned int maxiter;
double cx;
double cy;
} rendering_params_t;
5. Céčkovské funkce akceptující strukturu obsahující ukazatel
Ve druhém kroku upravíme hlavičky obou céčkovských funkcí, do kterých se bude předávat struktura (resp. přesněji řečeno ukazatel na strukturu) se všemi informacemi o rastrovém obrázku, tj. s jeho rozměry i ukazatelem na buffer hodnotami pixelů:
void render_mandelbrot(image_t *image,
const unsigned char *palette,
rendering_params_t *rendering_params) {
}
void render_julia(image_t *image,
const unsigned char *palette,
rendering_params_t *rendering_params) {
V tělech těchto funkcí dojde k nepatrným změnám, konkrétně při získání rozměrů obrázku a ukazatele na hodnoty (barvy) pixelů:
...
...
...
unsigned char *p = image->pixels;
...
...
...
cy = ymin;
for (y = 0; y < image->height; y++) {
cx = xmin;
for (x = 0; x < image->width; x++) {
Úplný zdrojový kód céčkovské části aplikace bude po všech provedených úpravách vypadat následovně:
#include "renderer.h"
void putpixel(unsigned char **pixel, const unsigned char *palette,
int color_index) {
int color_offset = color_index * 3;
unsigned char *pal = (unsigned char *)(palette + color_offset);
*(*pixel)++ = *pal++;
*(*pixel)++ = *pal++;
*(*pixel)++ = *pal;
(*pixel)++;
}
void render_mandelbrot(image_t *image,
const unsigned char *palette,
rendering_params_t *rendering_params) {
int x, y;
double cx, cy;
double xmin = -2.0, ymin = -1.5, xmax = 1.0, ymax = 1.5;
unsigned char *p = image->pixels;
cy = ymin;
for (y = 0; y < image->height; y++) {
cx = xmin;
for (x = 0; x < image->width; x++) {
double zx = 0.0;
double zy = 0.0;
unsigned int i = 0;
while (i < rendering_params->maxiter) {
double zx2 = zx * zx;
double zy2 = zy * zy;
if (zx2 + zy2 > 4.0) {
break;
}
zy = 2.0 * zx * zy + cy;
zx = zx2 - zy2 + cx;
i++;
}
putpixel(&p, palette, i);
cx += (xmax - xmin) / image->width;
}
cy += (ymax - ymin) / image->height;
}
}
void render_julia(image_t *image,
const unsigned char *palette,
rendering_params_t *rendering_params) {
int x, y;
double zx0, zy0;
double xmin = -1.5, ymin = -1.5, xmax = 1.5, ymax = 1.5;
unsigned char *p = image->pixels;
zy0 = ymin;
for (y = 0; y < image->height; y++) {
zx0 = xmin;
for (x = 0; x < image->width; x++) {
double zx = zx0;
double zy = zy0;
unsigned int i = 0;
while (i < rendering_params->maxiter) {
double zx2 = zx * zx;
double zy2 = zy * zy;
if (zx2 + zy2 > 4.0) {
break;
}
zy = 2.0 * zx * zy + rendering_params->cy;
zx = zx2 - zy2 + rendering_params->cx;
i++;
}
putpixel(&p, palette, i);
zx0 += (xmax - xmin) / image->width;
}
zy0 += (ymax - ymin) / image->height;
}
}
6. Volání upravených nativních funkcí z Pythonu s předáním struktury s ukazateli
Aby bylo možné obě výše uvedené nativní funkce volat a předat jim strukturu s ukazatelem, musíme v Pythonu vytvořit odpovídající třídu odvozenou od třídy ctypes.Structure. Pokusme se nejdříve v této třídě o definici prvku nazvaného pixels, jehož typ je ctypes.c_char_p. To by mělo být – alespoň na první pohled – korektní:
class Image(Structure):
_fields_ = [
("width", c_uint),
("height", c_uint),
("pixels", c_char_p)
]
Další postup již poměrně dobře známe. Nejdříve načteme dynamicky linkovanou knihovnu:
# try to load dynamically linked library
renderer = CDLL("./renderer.so")
Dále naalokujeme buffer pro celý obrázek. Velikost bufferu odpovídá rozlišení obrázku vynásobeného hodnotou 4 (RGBA):
# create buffer for raster image buffer = create_string_buffer(4 * IMAGE_WIDTH * IMAGE_HEIGHT)
Zkonstruujeme instanci třídy Image, a to včetně bufferu (odkazu na něj):
c_image_1 = Image(IMAGE_WIDTH, IMAGE_HEIGHT, buffer)
A následně se pokusíme zavolat nativní funkci s předáním ukazatele na c_image1:
# render Mandelbrot set into buffer
renderer.render_mandelbrot(
pointer(c_image_1), pal, pointer(rendering_params)
)
Totéž se pokusíme provést i pro druhý fraktál, který má být umístěn v samostatném obrázku:
c_image_2 = Image(IMAGE_WIDTH, IMAGE_HEIGHT, buffer) # render Julia set into buffer renderer.render_julia(pointer(c_image_2), pal, pointer(rendering_params)) image2 = image_from_buffer(buffer, IMAGE_WIDTH, IMAGE_HEIGHT, "RGBX")
7. Chování po spuštění
Ve skutečnosti je výše uvedená konstrukce třídy Image nekorektní, což se ovšem v Pythonu dozdíme až po spuštění skriptu:
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "/home/ptisnovs/src/most-popular-python-libs/ctypes/exampleH/show.py", line 117, in <module>
main()
File "/home/ptisnovs/src/most-popular-python-libs/ctypes/exampleH/show.py", line 99, in main
c_image_1 = Image(IMAGE_WIDTH, IMAGE_HEIGHT, buffer)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: incompatible types, c_char_Array_262144 instance instead of c_char_p instance
I když je to na první pohled poněkud zvláštní, neodpovídá typ ctypes.c_char_p datovému typu hodnoty vrácené z funkce ctypes.create_string_buffer. Pozor: toto je poměrně častá chyba, s níž se při práci s knihovnou ctypes setká prakticky každý.
8. Úplný zdrojový kód Pythonní části demonstračního příkladu
Pro úplnost i uveďme úplný zdrojový kód tohoto demonstračního příkladu, resp. přesněji řečeno jeho Pythonní části:
import sys
from ctypes import (
CDLL,
c_double,
c_int,
c_uint,
c_char_p,
create_string_buffer,
Structure,
pointer,
)
from palette_mandmap import palette
import pygame
import pygame.locals
TITLE = "Renderer"
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 300
IMAGE_WIDTH = 256
IMAGE_HEIGHT = 256
MAXITER = 150
def initialize_ui(title, width, height):
"""Initialize Pygame display, drawing surface, and clocks."""
# set window title
pygame.display.set_caption(title)
# initialize window
display = pygame.display.set_mode([width, height])
display.fill((0, 0, 0))
clock = pygame.time.Clock()
return display, clock
def palette_to_buffer(p):
s = create_string_buffer(len(p) * 3)
i = 0
for color in p:
s[i] = color[0]
s[i + 1] = color[1]
s[i + 2] = color[2]
i += 3
return s
def event_loop(display, image1, image2, clock):
while True:
for event in pygame.event.get():
if event.type == pygame.locals.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.locals.KEYDOWN:
if event.key == pygame.locals.K_ESCAPE:
pygame.quit()
sys.exit()
# all events has been processed - update scene and redraw the screen
display.blit(image1, (30, 20))
display.blit(image2, (60 + image1.get_width(), 20))
# and update the whole display
pygame.display.update()
clock.tick(25)
def image_from_buffer(buffer, width, height, fmt):
return pygame.image.frombytes(bytes(buffer), (width, height), fmt)
class Image(Structure):
_fields_ = [("width", c_uint), ("height", c_uint), ("pixels", c_char_p)]
class RenderingParams(Structure):
_fields_ = [("maxiter", c_uint), ("cx", c_double), ("cy", c_double)]
def main():
cx = -0.171119200000000013445
cy = 0.657309400000000000000
rendering_params = RenderingParams(MAXITER, cx, cy)
pal = palette_to_buffer(palette)
display, clock = initialize_ui(TITLE, SCREEN_WIDTH, SCREEN_HEIGHT)
# try to load dynamically linked library
renderer = CDLL("./renderer.so")
# create buffer for raster image
buffer = create_string_buffer(4 * IMAGE_WIDTH * IMAGE_HEIGHT)
c_image_1 = Image(IMAGE_WIDTH, IMAGE_HEIGHT, buffer)
# render Mandelbrot set into buffer
renderer.render_mandelbrot(
pointer(c_image_1), pal, pointer(rendering_params)
)
image1 = image_from_buffer(buffer, IMAGE_WIDTH, IMAGE_HEIGHT, "RGBX")
c_image_2 = Image(IMAGE_WIDTH, IMAGE_HEIGHT, buffer)
# render Julia set into buffer
renderer.render_julia(pointer(c_image_2), pal, pointer(rendering_params))
image2 = image_from_buffer(buffer, IMAGE_WIDTH, IMAGE_HEIGHT, "RGBX")
event_loop(display, image1, image2, clock)
if __name__ == "__main__":
main()
# finito
9. Korektní varianta předávání struktury obsahující ukazatel
V případě, že má struktura předávaná z Pythonu do jazyka C obsahovat ukazatel (nebo ukazatele), musíme postupovat nepatrně odlišně. Typ „ukazatel na typ X“ je nutné definovat formou:
ctypes.POINTER(typ)
Nejprve identifikátor POINTER (což je jméno vestavěné funkce) musíme importovat:
from ctypes import POINTER
Následně upravím definici třídy Image, která datovou strukturu popisuje:
class Image(Structure):
_fields_ = [
("width", c_uint),
("height", c_uint),
("pixels", POINTER(c_char))
]
10. Poslední varianta demonstračního příkladu: nativní i Pythonní část
Poslední – nyní již plně korektní – varianta demonstračního příkladu, ve kterém se z Pythonu volá nativní funkce a předává se jí struktura s ukazatelem, bude vypadat následovně.
Hlavičkový soubor s definicí struktur:
typedef struct {
unsigned int width;
unsigned int height;
unsigned char *pixels;
} image_t;
typedef struct {
unsigned int maxiter;
double cx;
double cy;
} rendering_params_t;
Nativní část aplikace naprogramovaná v jazyku C:
#include "renderer.h"
void putpixel(unsigned char **pixel, const unsigned char *palette,
int color_index) {
int color_offset = color_index * 3;
unsigned char *pal = (unsigned char *)(palette + color_offset);
*(*pixel)++ = *pal++;
*(*pixel)++ = *pal++;
*(*pixel)++ = *pal;
(*pixel)++;
}
void render_mandelbrot(image_t *image,
const unsigned char *palette,
rendering_params_t *rendering_params) {
int x, y;
double cx, cy;
double xmin = -2.0, ymin = -1.5, xmax = 1.0, ymax = 1.5;
unsigned char *p = image->pixels;
cy = ymin;
for (y = 0; y < image->height; y++) {
cx = xmin;
for (x = 0; x < image->width; x++) {
double zx = 0.0;
double zy = 0.0;
unsigned int i = 0;
while (i < rendering_params->maxiter) {
double zx2 = zx * zx;
double zy2 = zy * zy;
if (zx2 + zy2 > 4.0) {
break;
}
zy = 2.0 * zx * zy + cy;
zx = zx2 - zy2 + cx;
i++;
}
putpixel(&p, palette, i);
cx += (xmax - xmin) / image->width;
}
cy += (ymax - ymin) / image->height;
}
}
void render_julia(image_t *image,
const unsigned char *palette,
rendering_params_t *rendering_params) {
int x, y;
double zx0, zy0;
double xmin = -1.5, ymin = -1.5, xmax = 1.5, ymax = 1.5;
unsigned char *p = image->pixels;
zy0 = ymin;
for (y = 0; y < image->height; y++) {
zx0 = xmin;
for (x = 0; x < image->width; x++) {
double zx = zx0;
double zy = zy0;
unsigned int i = 0;
while (i < rendering_params->maxiter) {
double zx2 = zx * zx;
double zy2 = zy * zy;
if (zx2 + zy2 > 4.0) {
break;
}
zy = 2.0 * zx * zy + rendering_params->cy;
zx = zx2 - zy2 + rendering_params->cx;
i++;
}
putpixel(&p, palette, i);
zx0 += (xmax - xmin) / image->width;
}
zy0 += (ymax - ymin) / image->height;
}
}
Poslední část aplikace naprogramovaná v Pythonu, z něhož se volají nativní funkce:
import sys
from ctypes import (
CDLL,
c_double,
c_int,
c_uint,
c_char,
create_string_buffer,
Structure,
pointer,
POINTER,
)
from palette_mandmap import palette
import pygame
import pygame.locals
TITLE = "Renderer"
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 300
IMAGE_WIDTH = 256
IMAGE_HEIGHT = 256
MAXITER = 150
def initialize_ui(title, width, height):
"""Initialize Pygame display, drawing surface, and clocks."""
# set window title
pygame.display.set_caption(title)
# initialize window
display = pygame.display.set_mode([width, height])
display.fill((0, 0, 0))
clock = pygame.time.Clock()
return display, clock
def palette_to_buffer(p):
s = create_string_buffer(len(p) * 3)
i = 0
for color in p:
s[i] = color[0]
s[i + 1] = color[1]
s[i + 2] = color[2]
i += 3
return s
def event_loop(display, image1, image2, clock):
while True:
for event in pygame.event.get():
if event.type == pygame.locals.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.locals.KEYDOWN:
if event.key == pygame.locals.K_ESCAPE:
pygame.quit()
sys.exit()
# all events has been processed - update scene and redraw the screen
display.blit(image1, (30, 20))
display.blit(image2, (60 + image1.get_width(), 20))
# and update the whole display
pygame.display.update()
clock.tick(25)
def image_from_buffer(buffer, width, height, fmt):
return pygame.image.frombytes(bytes(buffer), (width, height), fmt)
class Image(Structure):
_fields_ = [("width", c_uint), ("height", c_uint), ("pixels", POINTER(c_char))]
class RenderingParams(Structure):
_fields_ = [("maxiter", c_uint), ("cx", c_double), ("cy", c_double)]
def main():
cx = -0.171119200000000013445
cy = 0.657309400000000000000
rendering_params = RenderingParams(MAXITER, cx, cy)
pal = palette_to_buffer(palette)
display, clock = initialize_ui(TITLE, SCREEN_WIDTH, SCREEN_HEIGHT)
# try to load dynamically linked library
renderer = CDLL("./renderer.so")
# create buffer for raster image
buffer = create_string_buffer(4 * IMAGE_WIDTH * IMAGE_HEIGHT)
c_image_1 = Image(IMAGE_WIDTH, IMAGE_HEIGHT, buffer)
# render Mandelbrot set into buffer
renderer.render_mandelbrot(
pointer(c_image_1), pal, pointer(rendering_params)
)
image1 = image_from_buffer(buffer, IMAGE_WIDTH, IMAGE_HEIGHT, "RGBX")
c_image_2 = Image(IMAGE_WIDTH, IMAGE_HEIGHT, buffer)
# render Julia set into buffer
renderer.render_julia(pointer(c_image_2), pal, pointer(rendering_params))
image2 = image_from_buffer(buffer, IMAGE_WIDTH, IMAGE_HEIGHT, "RGBX")
event_loop(display, image1, image2, clock)
if __name__ == "__main__":
main()
# finito
11. Bitová pole v jazyku C a Pythonu
V programovacím jazyku C lze definovat takzvaná bitová pole (bitfields). Opět se jedná o datové struktury, ovšem prvky těchto struktur neobsahují pouze své názvy a informace o typu, ale i počet bitů nutných pro uložení tohoto prvku. Je tak například možné specifikovat, že hodnota prvku x má být typu unsigned int a současně se má v paměti pro tento prvek rezervovat n bitů (například jeden bit, čtyři bity atd.). Bitová pole se často používají pro implementaci různých datových struktur, které (například) kromě ukazatelů obsahují i takzvané tagy. Taktéž se s nimi setkáme ve chvíli, kdy je nutné pracovat s HW registry, které mohou mít na jednotlivé bity namapovány různé informace. Příkladem může být uložení barvových atributů ve standardních textových režimech IBM PC:
╓7┬6┬5┬4┬3┬2┬1┬0╖ ║ │bkgnd│ frgnd ║ ╙─┴─┴─┴─┴─┴─┴─┴─╜ bity ║ ╚═╦═╝ ╚═════╩═► 0-3: barva popředí 0-15 ║ ╚═══════════► 4-6: barva pozadí 0-7 ╚═══════════════► 7: povolení blikání
Jak již bylo napsáno výše, je podpora bitových polí v jazyku C jednoduchá, ovšem při volání céčkovských funkcí musíme umět s bitovými poli pracovat i v Pythonu.
12. Předání běžné struktury (nikoli bitového pole) hodnotou a odkazem
Podívejme se na velmi jednoduchý příklad, ve kterém budeme chtít (po dalších úpravách) volat nativní funkce a předávat jim bitové pole, a to buď hodnotou nebo odkazem. Prozatím namísto skutečného bitového pole využijeme běžnou strukturu:
#include <stdio.h>
typedef struct {
unsigned int a;
unsigned int b;
unsigned int c;
} my_struct;
void test_pass_by_value(my_struct s) {
printf("a=%u\nb=%u\nc=%u\n", s.a, s.b, s.c);
}
void test_pass_by_reference(my_struct *s) {
printf("a=%u\nb=%u\nc=%u\n", s->a, s->b, s->c);
}
V Pythonu budeme strukturu (opět – prozatím ne bitové pole) deklarovat takto:
class MyStruct(Structure):
_fields_ = [
("a", c_uint),
("b", c_uint),
("c", c_uint),
]
Volání nativních funkcí z Pythonu:
import sys
from ctypes import (
CDLL,
c_int,
c_uint,
Structure,
pointer,
POINTER,
)
class MyStruct(Structure):
_fields_ = [
("a", c_uint),
("b", c_uint),
("c", c_uint),
]
def main():
# try to load dynamically linked library
bitfield = CDLL("./bitfield.so")
my_struct = MyStruct(1, 2, 3)
# pass my value
print("Pass struct by value:")
bitfield.test_pass_by_value(my_struct)
print()
# pass my reference
print("Pass struct by reference:")
bitfield.test_pass_by_reference(pointer(my_struct))
if __name__ == "__main__":
main()
# finito
Chování po spuštění naznačuje, že je vše v pořádku:
Pass struct by value: a=1 b=2 c=3 Pass struct by reference: a=1 b=2 c=3
13. Definice bitového pole v jazyku C
Nyní přejdeme od běžných datových struktur ke skutečným bitovým polím. Nejdříve si takové pole nadefinujeme v jazyku C:
typedef struct {
unsigned int a:5;
unsigned int b:6;
unsigned int c:7;
} my_struct;
Celá nativní část s funkcemi, které akceptují jako své parametry bitové pole předávané hodnotou nebo odkazem, vypadá následovně:
#include <stdio.h>
typedef struct {
unsigned int a:5;
unsigned int b:6;
unsigned int c:7;
} my_struct;
void test_pass_by_value(my_struct s) {
printf("a=%u\nb=%u\nc=%u\n", s.a, s.b, s.c);
}
void test_pass_by_reference(my_struct *s) {
printf("a=%u\nb=%u\nc=%u\n", s->a, s->b, s->c);
}
14. Definice struktury v Pythonu bez ohledu na bitové šířky prvků
Pokusme se v Pythonní části naší testací aplikace definovat datovou strukturu s běžnými prvky, nikoli s bitovými poli:
class MyStruct(Structure):
_fields_ = [
("a", c_uint),
("b", c_uint),
("c", c_uint),
]
Zajímavé je, že knihovna ctypes, která většinou velmi dobře hlídá datové typy (někdy až příliš přísně), v tomto případě nebude vypisovat žádné chyby ani varování a umožní nám výše uvedenou strukturu předat do céčkovských (nativních) funkcí:
import sys
from ctypes import (
CDLL,
c_int,
c_uint,
Structure,
pointer,
POINTER,
)
class MyStruct(Structure):
_fields_ = [
("a", c_uint),
("b", c_uint),
("c", c_uint),
]
def main():
# try to load dynamically linked library
bitfield = CDLL("./bitfield.so")
my_struct = MyStruct(1, 2, 3)
# pass my value
print("Pass struct by value:")
bitfield.test_pass_by_value(my_struct)
print()
# pass my reference
print("Pass struct by reference:")
bitfield.test_pass_by_reference(pointer(my_struct))
if __name__ == "__main__":
main()
# finito
Ovšem po spuštění je patrné, že výsledky nejsou korektní, protože se nevypsaly hodnoty 1, 2 a 3, ale hodnoty 1, 0 a 0. Evidentně si tedy Pythonní část aplikace s céčkovou částí příliš nerozumí:
Pass struct by value: a=1 b=0 c=0 Pass struct by reference: a=1 b=0 c=0
15. Definice struktury v Pythonu s ohledem na bitové šířky prvků
Aby se korektně naplnily i prvky struktury s bitovými poli, musíme (v Pythonu) provést správnou a kompatibilní deklaraci takové struktury. Konkrétně to znamená, že v deklaraci musíme uvést i počet bitů jednotlivých prvků. To se provede snadno – přidáním třetí informace k prvku. Uvedeme tedy jeho jméno, datový typ a počet bitů:
class MyStruct(Structure):
_fields_ = [
("a", c_uint, 5),
("b", c_uint, 6),
("c", c_uint, 7),
]
16. Korektní způsob předání bitového pole z Pythonu do nativní funkce
Upravený (či možná lépe řečeno opravený) kód v Pythonu bude vypadat následovně:
import sys
from ctypes import (
CDLL,
c_int,
c_uint,
Structure,
pointer,
POINTER,
)
class MyStruct(Structure):
_fields_ = [
("a", c_uint, 5),
("b", c_uint, 6),
("c", c_uint, 7),
]
def main():
# try to load dynamically linked library
bitfield = CDLL("./bitfield.so")
my_struct = MyStruct(1, 2, 3)
# pass my value
print("Pass struct by value:")
bitfield.test_pass_by_value(my_struct)
print()
# pass my reference
print("Pass struct by reference:")
bitfield.test_pass_by_reference(pointer(my_struct))
if __name__ == "__main__":
main()
# finito
Nyní po spuštění dostaneme korektní hodnoty – obě části aplikace si tedy dobře rozumí:
Pass struct by value: a=1 b=2 c=3 Pass struct by reference: a=1 b=2 c=3
17. Zarovnání prvků ve strukturách
V programovacím jazyku C jsou definována pravidla určující způsob zarovnání prvků ve strukturách (alignment). Tato pravidla mohou být relativně komplikovaná a obecně řečeno je nutné je znát zejména ve chvíli, kdy jsou datové struktury předávány mezi různými programovacími jazyky. Ovšem při použití knihovny ctypes jsme (většinou) této práce ušetřeni, protože ctypes používá stejná pravidla, jako překladač jazyka C. Ovšem v případě potřeby je možné i zarovnání řídit (jak na straně C, tak i Pythonu), což je relativně komplikované téma (navíc závislé na použité architektuře), kterému se budeme podrobněji věnovat v závěrečném článku.
18. Repositář s demonstračními příklady
V předminulém, minulém i dnešním článku popsané demonstrační příklady naleznete na GitHubu:
Navíc si pro úplnost uveďme demonstrační příklady použité v článcích o knihovně cffi. I v těchto článcích jsme se totiž o ctypes zmiňovali:
| # | Příklad | Stručný popis | Adresa |
|---|---|---|---|
| 1 | adder/adder.c | funkce psaná v C, která sečte své dva celočíselné parametry | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/adder/adder.c |
| 2 | adder/call_via_cffi1.py | zavolání céčkovské funkce přes cffi s korektními parametry | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/adder/call_via_cffi1.py |
| 3 | adder/call_via_cffi2.py | zavolání céčkovské funkce přes cffi s nekorektními parametry | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/adder/call_via_cffi2.py |
| 4 | adder/call_via_cffi3.py | zavolání céčkovské funkce přes cffi s nekorektními parametry | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/adder/call_via_cffi3.py |
| 5 | adder/call_via_cffi.sh | nastavení cest a spuštění všech tří předchozích Pythonovských skriptů | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/adder/call_via_cffi.sh |
| 6 | adder/call_via_ctypes1.py | zavolání céčkovské funkce přes ctypes s korektními parametry | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/adder/call_via_ctypes1.py |
| 7 | adder/call_via_ctypes2.py | zavolání céčkovské funkce přes ctypes s nekorektními parametry | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/adder/call_via_ctypes2.py |
| 8 | adder/call_via_ctypes3.py | zavolání céčkovské funkce přes ctypes s nekorektními parametry | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/adder/call_via_ctypes3.py |
| 9 | adder/call_via_ctypes.sh | nastavení cest a spuštění všech tří předchozích Pythonovských skriptů | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/adder/call_via_ctypes.sh |
| 10 | adder/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/adder/make_library.sh |
| 11 | adder/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/adder/clean.sh |
| 12 | greeter/greeter.c | funkce psaná v C, která na standardní výstup vytiskne řetězec | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter/greeter.c |
| 13 | greeter/call_via_cffi1.py | zavolání céčkovské funkce přes cffi s nekorektním parametrem | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter/call_via_cffi1.py |
| 14 | greeter/call_via_cffi2.py | zavolání céčkovské funkce přes cffi s korektním parametrem | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter/call_via_cffi2.py |
| 15 | greeter/call_via_cffi3.py | zavolání céčkovské funkce přes cffi s korektním parametrem | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter/call_via_cffi3.py |
| 16 | greeter/call_via_cffi.sh | nastavení cest a spuštění všech tří předchozích Pythonovských skriptů | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter/call_via_cffi.sh |
| 17 | greeter/call_via_ctypes1.py | zavolání céčkovské funkce přes ctypes s nekorektním parametrem | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter/call_via_ctypes1.py |
| 18 | greeter/call_via_ctypes2.py | zavolání céčkovské funkce přes ctypes s korektním parametrem | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter/call_via_ctypes2.py |
| 19 | greeter/call_via_ctypes3.py | zavolání céčkovské funkce přes ctypes s korektním parametrem | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter/call_via_ctypes3.py |
| 20 | greeter/call_via_ctypes.sh | nastavení cest a spuštění všech tří předchozích Pythonovských skriptů | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter/call_via_ctypes.sh |
| 21 | greeter/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter/make_library.sh |
| 22 | greeter/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter/clean.sh |
| 23 | swapper/swapper.c | céčkovská funkce prohazující obsah svých dvou parametrů předávaných referencí | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/swapper/swapper.c |
| 24 | swapper/call_via_cffi1.py | zavolání céčkovské knihovny z jazyka Python (korektní varianta) | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/swapper/call_via_cffi1.py |
| 25 | swapper/call_via_cffi2.py | zavolání céčkovské knihovny z jazyka Python (nekorektní varianta) | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/swapper/call_via_cffi2.py |
| 26 | swapper/call_via_cffi.sh | nastavení cest a spuštění Pythonovského skriptu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/swapper/call_via_cffi.sh |
| 27 | swapper/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/swapper/make_library.sh |
| 28 | swapper/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/swapper/clean.sh |
| 29 | filler/filler.c | céčkovská funkce pro vyplnění části pole zadanou hodnotou | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/filler/filler.c |
| 30 | filler/call_via_cffi.py | zavolání céčkovské knihovny z jazyka Python | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/filler/call_via_cffi.py |
| 31 | filler/call_via_cffi.sh | nastavení cest a spuštění Pythonovského skriptu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/filler/call_via_cffi.sh |
| 32 | filler/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/filler/make_library.sh |
| 32 | filler/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/filler/clean.sh |
| 33 | greeter_h/greeter.c | funkce psaná v C, která na standardní výstup vytiskne řetězec | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h/greeter.c |
| 34 | greeter_h/greeter.h | prototyp (předběžná deklarace) funkce greeter | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h/greeter.h |
| 35 | greeter_h/call_via_cffi4.py | zavolání céčkovské knihovny z jazyka Python | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h/call_via_cffi4.py |
| 36 | greeter_h/call_via_cffi.sh | nastavení cest a spuštění Pythonovského skriptu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h/call_via_cffi.sh |
| 37 | greeter_h/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h/make_library.sh |
| 38 | greeter_h/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h/clean.sh |
| 39 | greeter_h2/greeter.c | funkce psaná v C, která na standardní výstup vytiskne řetězec | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h2/greeter.c |
| 40 | greeter_h2/greeter.h | prototyp (předběžná deklarace) funkce greeter obalená v testu na existenci symbolu/makra | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h2/greeter.h |
| 41 | greeter_h2/call_via_cffi5.py | zavolání céčkovské knihovny z jazyka Python | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h2/call_via_cffi5.py |
| 42 | greeter_h2/call_via_cffi.sh | nastavení cest a spuštění Pythonovského skriptu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h2/call_via_cffi.sh |
| 43 | greeter_h2/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h2/make_library.sh |
| 44 | greeter_h2/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h2/clean.sh |
| 45 | greeter_h3/greeter.c | funkce psaná v C, která na standardní výstup vytiskne řetězec | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h3/greeter.c |
| 46 | greeter_h3/greeter.h | test na existenci symbolu/makra, pokud makro neexistuje, provede se vložení dalšího souboru | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h3/greeter.h |
| 47 | greeter_h3/_greeter.h | prototyp (předběžná deklarace) funkce greeter bez dalších informací | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h3/_greeter.h |
| 48 | greeter_h3/call_via_cffi5.py | zavolání céčkovské funkce z knihovny z jazyka Python | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h3/call_via_cffi5.py |
| 49 | greeter_h3/call_via_cffi.sh | nastavení cest a spuštění Pythonovského skriptu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h3/call_via_cffi.sh |
| 50 | greeter_h3/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h3/make_library.sh |
| 51 | greeter_h3/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_h3/clean.sh |
| 52 | greeter_build/greeter.c | funkce psaná v C, která na standardní výstup vytiskne řetězec | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_build/greeter.c |
| 53 | greeter_build/greeter.h | prototyp (předběžná deklarace) funkce greeter bez dalších informací | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_build/greeter.h |
| 54 | greeter_build/call_via_cffi7.py | skript pro překlad céčkovské funkce, vytvoření dynamicky linkované knihovny a zavolání funkce z této knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_build/call_via_cffi7.py |
| 55 | greeter_build/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/greeter_build/clean.sh |
| 56 | vector_printer/vector_printer.c | funkce psaná v C, která akceptuje jako svůj parametr strukturu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/vector_printer/vector_printer.c |
| 57 | vector_printer/vector_printer.h | prototyp (předběžná deklarace) funkce print_vector bez dalších informací | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/vector_printer/vector_printer.h |
| 58 | vector_printer/call_via_cffi.sh | zavolání céčkovské funkce z knihovny z jazyka Python | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/vector_printer/call_via_cffi.sh |
| 59 | vector_printer/call_via_cffi.py | nastavení cest a spuštění Pythonovského skriptu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/vector_printer/call_via_cffi.py |
| 60 | vector_printer/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/vector_printer/make_library.sh |
| 61 | vector_printer/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/vector_printer/clean.sh |
| 62 | vector_printer2/vector_printer.c | funkce psaná v C, která akceptuje jako svůj parametr ukazatel na strukturu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/vector_printer2/vector_printer.c |
| 63 | vector_printer2/vector_printer.h | prototyp (předběžná deklarace) funkce print_vector bez dalších informací | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/vector_printer2/vector_printer.h |
| 64 | vector_printer2/call_via_cffi.sh | zavolání céčkovské funkce z knihovny z jazyka Python | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/vector_printer2/call_via_cffi.sh |
| 65 | vector_printer2/call_via_cffi.py | nastavení cest a spuštění Pythonovského skriptu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/vector_printer2/call_via_cffi.py |
| 66 | vector_printer2/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/vector_printer2/make_library.sh |
| 67 | vector_printer2/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/vector_printer2/clean.sh |
| 68 | array_printer1/array_printer.c | funkce naprogramovaná v C, která akceptuje pole s prvky typu float | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer1/array_printer.c |
| 69 | array_printer1/array_printer.h | prototyp (předběžná deklarace) funkce print_array bez dalších informací | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer1/array_printer.h |
| 70 | array_printer1/call_via_cffi.py | zavolání céčkovské funkce z knihovny z jazyka Python | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer1/call_via_cffi.sh |
| 71 | array_printer1/call_via_cffi.sh | nastavení cest a spuštění Pythonovského skriptu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer1/call_via_cffi.py |
| 72 | array_printer1/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer1/make_library.sh |
| 73 | array_printer1/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer1/clean.sh |
| 74 | array_printer2/array_printer.c | funkce naprogramovaná v C, která akceptuje pole s prvky typu float | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer2/array_printer.c |
| 75 | array_printer2/array_printer.h | prototyp (předběžná deklarace) funkce print_array bez dalších informací | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer2/array_printer.h |
| 76 | array_printer2/call_via_cffi.py | zavolání céčkovské funkce z knihovny z jazyka Python | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer2/call_via_cffi.sh |
| 77 | array_printer2/call_via_cffi.sh | nastavení cest a spuštění Pythonovského skriptu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer2/call_via_cffi.py |
| 78 | array_printer2/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer2/make_library.sh |
| 79 | array_printer2/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer2/clean.sh |
| 80 | array_printer3/array_printer.c | funkce naprogramovaná v C, která akceptuje pole s prvky typu float | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer3/array_printer.c |
| 81 | array_printer3/array_printer.h | prototyp (předběžná deklarace) funkce print_array bez dalších informací | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer3/array_printer.h |
| 82 | array_printer3/call_via_cffi.py | zavolání céčkovské funkce z knihovny z jazyka Python | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer3/call_via_cffi.sh |
| 83 | array_printer3/call_via_cffi.sh | nastavení cest a spuštění Pythonovského skriptu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer3/call_via_cffi.py |
| 84 | array_printer3/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer3/make_library.sh |
| 85 | array_printer3/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer3/clean.sh |
| 86 | array_printer4/array_printer.c | funkce naprogramovaná v C, která akceptuje pole s prvky typu float | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer4/array_printer.c |
| 87 | array_printer4/array_printer.h | prototyp (předběžná deklarace) funkce print_array bez dalších informací | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer4/array_printer.h |
| 88 | array_printer4/call_via_cffi.py | zavolání céčkovské funkce z knihovny z jazyka Python | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer4/call_via_cffi.sh |
| 89 | array_printer4/call_via_cffi.sh | nastavení cest a spuštění Pythonovského skriptu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer4/call_via_cffi.py |
| 90 | array_printer4/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer4/make_library.sh |
| 91 | array_printer4/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer4/clean.sh |
| 92 | array_printer5/array_printer.c | funkce naprogramovaná v C, která akceptuje pole s prvky typu vector_t | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer5/array_printer.c |
| 93 | array_printer5/array_printer.h | prototyp (předběžná deklarace) funkce print_array bez dalších informací | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer5/array_printer.h |
| 94 | array_printer5/call_via_cffi.py | zavolání céčkovské funkce z knihovny z jazyka Python | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer5/call_via_cffi.sh |
| 95 | array_printer5/call_via_cffi.sh | nastavení cest a spuštění Pythonovského skriptu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer5/call_via_cffi.py |
| 96 | array_printer5/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer5/make_library.sh |
| 97 | array_printer5/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer5/clean.sh |
| 92 | array_printer6/array_printer.c | funkce naprogramovaná v C, která akceptuje dvourozměrné pole s prvky typu float | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer6/array_printer.c |
| 93 | array_printer6/array_printer.h | prototyp (předběžná deklarace) funkce print_array bez dalších informací | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer6/array_printer.h |
| 94 | array_printer6/call_via_cffi.py | zavolání céčkovské funkce z knihovny z jazyka Python | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer6/call_via_cffi.sh |
| 95 | array_printer6/call_via_cffi.sh | nastavení cest a spuštění Pythonovského skriptu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer6/call_via_cffi.py |
| 96 | array_printer6/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer6/make_library.sh |
| 97 | array_printer6/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer6/clean.sh |
| 98 | array_printer7/array_printer.c | funkce naprogramovaná v C, která akceptuje dvourozměrné pole s prvky typu float | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer7/array_printer.c |
| 99 | array_printer7/array_printer.h | prototyp (předběžná deklarace) funkce print_array bez dalších informací | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer7/array_printer.h |
| 100 | array_printer7/call_via_cffi.py | zavolání céčkovské funkce z knihovny z jazyka Python | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer7/call_via_cffi.sh |
| 101 | array_printer7/call_via_cffi.sh | nastavení cest a spuštění Pythonovského skriptu | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer7/call_via_cffi.py |
| 102 | array_printer7/make_library.sh | skript pro překlad céčkovské funkce a vytvoření dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer7/make_library.sh |
| 103 | array_printer7/clean.sh | skript pro smazání objektového souboru i dynamicky linkované knihovny | https://github.com/tisnik/most-popular-python-libs/blob/master/cffi/array_printer7/clean.sh |
19. Odkazy na Internetu
- ctypes – A foreign function library for Python
https://docs.python.org/3/library/ctypes.html - Pygame: display
https://www.pygame.org/docs/ref/display.html - Pygame: event
https://www.pygame.org/docs/ref/event.html - Pygame: image
https://www.pygame.org/docs/ref/image.html - Pygame: clock
https://www.pygame.org/docs/ref/time.html#pygame.time.Clock - Fraktály v počítačové grafice XII
https://www.root.cz/clanky/fraktaly-v-pocitacove-grafice-xii/ - Fraktály v počítačové grafice XIII
https://www.root.cz/clanky/fraktaly-v-pocitacove-grafice-xiii/ - Fraktály v počítačové grafice XIV
https://www.root.cz/clanky/fraktaly-v-pocitacove-grafice-xiv/ - CFFI documentation
https://cffi.readthedocs.io/en/latest/ - cffi 1.15.1 na PyPi
https://pypi.org/project/cffi/ - Python Bindings: Calling C or C++ From Python
https://realpython.com/python-bindings-overview/ - Interfacing with C/C++ Libraries
https://docs.python-guide.org/scenarios/clibs/ - Cython, pybind11, cffi – which tool should you choose?
http://blog.behnel.de/posts/cython-pybind11-cffi-which-tool-to-choose.html - Python FFI with ctypes and cffi
https://eli.thegreenplace.net/2013/03/09/python-ffi-with-ctypes-and-cffi - Propojení Go s Pythonem s využitím cgo a ctypes
https://www.root.cz/clanky/propojeni-go-s-pythonem-s-vyuzitim-cgo-a-ctypes/ - Propojení Go s Pythonem s využitím cgo a ctypes (2. část)
https://www.root.cz/clanky/propojeni-go-s-pythonem-s-vyuzitim-cgo-a-ctypes-2-cast/ - Programovací jazyk Rust: použití FFI pro volání funkcí z nativních knihoven
https://www.root.cz/clanky/programovaci-jazyk-rust-pouziti-ffi-pro-volani-funkci-z-nativnich-knihoven/ - Programovací jazyk Rust: použití FFI při předávání struktur
https://www.root.cz/clanky/programovaci-jazyk-rust-pouziti-ffi-pri-predavani-struktur/ - Programovací jazyk Rust: použití FFI pro volání funkcí z nativních knihoven (2. část)
https://www.root.cz/clanky/programovaci-jazyk-rust-pouziti-ffi-pro-volani-funkci-z-nativnich-knihoven-2-cast/ - Dynamic-link library
https://en.wikipedia.org/wiki/Dynamic-link_library - Úvod do jazyka C: Deklarace funkcí
https://www.fi.muni.cz/usr/jkucera/pb071/sl5.htm - Using standard library headers with CFFI
https://stackoverflow.com/questions/57481873/using-standard-library-headers-with-cffi - Preparing and Distributing modules
https://cffi.readthedocs.io/en/latest/cdef.html - C Arrays
https://www.programiz.com/c-programming/c-arrays - C Arrays
https://www.w3schools.com/c/c_arrays.php - Array of Structures in C
https://overiq.com/c-programming-101/array-of-structures-in-c/#google_vignette - C Structures (structs)
https://www.w3schools.com/c/c_structs.php - C Structs and pointers
https://www.programiz.com/c-programming/c-structures-pointers - Bit Fields in C
https://www.geeksforgeeks.org/c/bit-fields-c/ - C Alignment Cheatsheet
https://github.com/Q1CHENL/c-alignment-cheatsheet - GNU C Language Manual
https://www.gnu.org/software/c-intro-and-ref/manual/html_node/index.html - C Intro: 15 Structures
https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Structures.html - C Intro: 15.7 Bit Fields
https://www.gnu.org/software/c-intro-and-ref/manual/html_node/Bit-Fields.html
