Dies ist die Support Website des Buches:

Das Python Praxisbuch
Der große Profi-Leitfaden für Programmierer
Farid Hajji
Addison Wesley / Pearson Education
ISBN 978-3-8273-2543-3 (Sep 2008), 1298 Seiten.

11. Python und C/C++

ctypes

Die ctypes-Datentypwrapper

Komplexe Datentypen

Die Funktionen assctime und erand48:

char *   asctime(const struct tm *);   /* <time.h> */
double   erand48(unsigned short[3]);   /* <stdlib.h> */

ctypes-Pointer

ctypes-Strukturen und -Unions

Die C-Structur tm:

struct tm {
        int     tm_sec;         /* seconds after the minute [0-60] */
        int     tm_min;         /* minutes after the hour [0-59] */
        int     tm_hour;        /* hours since midnight [0-23] */
        int     tm_mday;        /* day of the month [1-31] */
        int     tm_mon;         /* months since January [0-11] */
        int     tm_year;        /* years since 1900 */
        int     tm_wday;        /* days since Sunday [0-6] */
        int     tm_yday;        /* days since January 1 [0-365] */
        int     tm_isdst;       /* Daylight Savings Time flag */
        long    tm_gmtoff;      /* offset from UTC in seconds */
        char    *tm_zone;       /* timezone abbreviation */
};
#!/usr/bin/env python
# time_tm.py -- ctypes wrapper for <time.h> struct tm;

from ctypes import Structure, c_int, c_long, c_char_p

class tm(Structure):
    _fields_ = [ ("tm_sec", c_int),     # seconds after the minute [0-60]
                 ("tm_min", c_int),     # minutes after the hour [0-59]
                 ("tm_hour", c_int),    # hours since midnight [0-23]
                 ("tm_mday", c_int),    # day of the month [1-31]
                 ("tm_mon", c_int),     # months since January [0-11]
                 ("tm_year", c_int),    # years since 1900
                 ("tm_wday", c_int),    # days since Sunday [0-6]
                 ("tm_yday", c_int),    # days since January 1 [0-365]
                 ("tm_isdst", c_int),   # Daylight Savings Time flag 
                 ("tm_gmtoff", c_long), # offset from UTC in seconds
                 ("tm_zone", c_char_p), # timezone abbreviation
               ]

time_tm.py

ctypes-Arrays

Die Klasse XZY:

class XZY(Structure):
    _fields_ = [ ("point", c_ushort * 3),
                 ("rgb",   c_ubyte  * 3)
               ]

C-Funktionen aufrufen

Funktionen aus Bibliotheken laden

URLs:

Screenshots:

Aus der Unix libc laden:

from ctypes import *

libc = cdll.LoadLibrary("libc.so")

libc.sleep(5)

Aus Windows DLLs laden:

from ctypes import *

kernel32 = windll.kernel32
user32 = windll.user32
msvcrt = cdll.msvcrt

MessageBoxW = user32.MessageBoxW

MessageBoxW(0, u'A Unicode Message: ÄÖÜäöüß', u'A Unicode Greeter', 0)

Hier hatte MessageBox (ANSI und Wide) die Signatur:

int MessageBox(
    HWND hWnd,
    LPCTSTR lpText,
    LPCTSTR lpCaption,
    UINT uType
);

Und printf ruft man so aus:

>>> from ctypes import *

>>> printf = cdll.msvcrt.printf

>>> result = printf("Hello, %s. You are %d years old.\n",
...                 "John", 39)
Hello, John. You are 39 years old.

>>> result
35

Zwei einfache Funktionen: time und sleep

URLs:

Screenshots:

Argument- und Rückgabewerte spezifizieren: cos

URLs:

Funktionen, die Strings auslesen: getenv, setenv

char *getenv(const char *name);
int   setenv(const char *name, const char *value, int overwrite);

Die nötigen Vorbereitungen:

from ctypes import *
libc = cdll.LoadLibrary("libc.so")

getenv = libc.getenv
setenv = libc.setenv

getenv.argtypes = [c_char_p]
getenv.restype = c_char_p

setenv.argtypes = [c_char_p, c_char_p, c_int]
setenv.restype = c_int

URLs:

Funktionen, die in einen Puffer schreiben

int gethostname(char *name, size_t namelen);  /* <unistd.h> */

Die nötigen Vorbereitungen:

from ctypes import *
libc = cdll.LoadLibrary("libc.so")

gethostname = libc.gethostname
gethostname.argtypes = [c_char * 255, c_uint]
gethostname.restype = c_int

buf = create_string_buffer(255)

URLS:

DWORD WINAPI GetEnvironmentVariable(
  __in_opt   LPCTSTR lpName,
  __out_opt  LPTSTR lpBuffer,
  __in       DWORD nSize
);

Screenshots:

Funktionen mit struct und pointer: gmtime, asctime

time_t      time(time_t *tloc);           /* <time.h> */
struct tm * gmtime(const time_t *clock);  /* <time.h> */
char *      asctime(const struct tm *tm); /* <time.h> */

URLs:

SWIG

URLs:

SWIG installieren

URLs:

SWIG unter Unix installieren

SWIG unter Windows installieren

Screenshots:

SWIG aufrufen

%module sleeper

unsigned int sleep(unsigned int seconds);

sleeper.i

#!/usr/bin/env python

from distutils.core import setup, Extension

sleeper_module = Extension('_sleeper',
                           sources = ['sleeper_wrap.c', ],
                          )

setup(name        = 'sleeper',
      version     = '0.1',
      author      = 'Farid Hajji',
      description = '''Wrapping sleep(3)''',
      ext_modules = [sleeper_module],
      py_modules  = ["sleeper"],
     )

sleeper_setup.py

C-Code mitkompilieren

/* deepthought.h -- a complex function */

#ifndef _DEEPTHOUGHT_H_
#define _DEEPTHOUGHT_H_

#define THE_ANSWER 42

extern int answer(void);

#endif /* _DEEPTHOUGHT_H_ */

deepthought.h

/* deepthought.c -- a complex function */

#include "deepthought.h"

int answer(void) {
  return THE_ANSWER;
}

deepthought.c

%module deepthought

%{
#include "deepthought.h"
%}

int answer(void);

deepthought.i

#!/usr/bin/env python

from distutils.core import setup, Extension

deepthought_module = Extension('_deepthought',
                               sources = ['deepthought.c',
                                          'deepthought_wrap.c', ],
                               )

setup(name        = 'deepthought',
      version     = '0.1',
      author      = 'Farid Hajji',
      description = '''A complex function''',
      ext_modules = [deepthought_module],
      py_modules  = ["deepthought"],
     )

deepthought_setup.py

Screenshots:

Konstanten und Variablen

Konstanten

/* math_constants.h -- some math.h constants */

#ifndef _MATH_CONSTANTS_H_
#define _MATH_CONSTANTS_H_

#define	MM_E		2.7182818284590452354	/* e */
#define	MM_LOG2E	1.4426950408889634074	/* log 2e */
#define	MM_LOG10E	0.43429448190325182765	/* log 10e */
#define	MM_LN2		0.69314718055994530942	/* log e2 */
#define	MM_LN10		2.30258509299404568402	/* log e10 */

#define	MMAXFLOAT	((float)3.40282346638528860e+38)

enum Integers { ZERO, ONE, TWO, THREE, FOUR, FIVE };

const double MM_PI = 3.14159265358979323846;    /* pi */
const double MM_PI_2 = 1.57079632679489661923;  /* pi/2 */
const double MM_PI_4 = 0.78539816339744830962;  /* pi/4 */

#endif /* _MATH_CONSTANTS_H_ */

math_constants.h

%module math_constants

%{
#include "math_constants.h"
%}

#define	MM_E		2.7182818284590452354	/* e */
#define	MM_LOG2E	1.4426950408889634074	/* log 2e */
#define	MM_LOG10E	0.43429448190325182765	/* log 10e */
#define	MM_LN2		0.69314718055994530942	/* log e2 */
#define	MM_LN10		2.30258509299404568402	/* log e10 */

#define	MMAXFLOAT	((float)3.40282346638528860e+38)

enum Integers { ZERO, ONE, TWO, THREE, FOUR, FIVE };

%constant double MM_PI;
%constant double MM_PI_2;
%constant double MM_PI_4;

math_constants.i

#!/usr/bin/env python

from distutils.core import setup, Extension

math_constants_module = Extension('_math_constants',
                                  sources = ['math_constants_wrap.c',],
                                 )

setup(name        = 'math_constants',
      version     = '0.1',
      author      = 'Farid Hajji',
      description = '''Wrapping constants in math_constants.h''',
      ext_modules = [math_constants_module],
      py_modules  = ["math_constants"],
     )

math_constants_setup.py

Globale Variablen: cvar

/* globvar.h -- global variables */

#ifndef _GLOBVAR_H_
#define _GLOBVAR_H_

extern int get_value(void);
extern void set_value(int value);

extern int global_var;

#endif /* _GLOBVAR_H_ */

globvar.h

/* globvar.c -- global variables */

#include "globvar.h"

int
get_value(void) {
  return global_var;
}

void
set_value(int value) {
  global_var = value;
}

/* A global variable shared by set_value and get_value */
int global_var = 0;

globvar.c

%module globvar

%{
#include "globvar.h"
%}

extern int get_value(void);
extern void set_value(int value);

extern int global_var;

globvar.i

#!/usr/bin/env python

from distutils.core import setup, Extension

globvar_module = Extension('_globvar',
                           sources = ['globvar_wrap.c',
                                      'globvar.c'],
                          )

setup(name        = 'globvar',
      version     = '0.1',
      author      = 'Farid Hajji',
      description = '''Wrapping a global variable''',
      ext_modules = [globvar_module],
      py_modules  = ["globvar"],
     )

globvar_setup.py

%module globvar_ro

%{
#include "globvar.h"
%}

extern int get_value(void);
extern void set_value(int value);

%immutable;
extern int global_var;
%mutable;

globvar_ro.i

#!/usr/bin/env python

from distutils.core import setup, Extension

globvar_ro_module = Extension('_globvar_ro',
                              sources = ['globvar_ro_wrap.c',
                                         'globvar.c'],
                          )

setup(name        = 'globvar_ro',
      version     = '0.1',
      author      = 'Farid Hajji',
      description = '''Wrapping a global variable''',
      ext_modules = [globvar_ro_module],
      py_modules  = ["globvar_ro"],
     )

globvar_ro_setup.py

%module globvar_noglobals

%{
#include "globvar.h"
%}

extern int get_value(void);
extern void set_value(int value);

globvar_noglobals.i

#!/usr/bin/env python

from distutils.core import setup, Extension

globvar_noglobals_module = Extension('_globvar_noglobals',
                           sources = ['globvar_noglobals_wrap.c',
                                      'globvar.c'],
                          )

setup(name        = 'globvar_noglobals',
      version     = '0.1',
      author      = 'Farid Hajji',
      description = '''Wrapping a global variable''',
      ext_modules = [globvar_noglobals_module],
      py_modules  = ["globvar_noglobals"],
     )

globvar_noglobals_setup.py

Stringmanipulationen

C-Funktionen, die Strings lesen

char *getenv(const char *name);
int   setenv(const char *name, const char *value, int overwrite);

URLs:

%module environ
%{
#include <stdlib.h>
%}

char *getenv(const char *name);
int setenv(const char *name, const char *value, int overwrite);

environ.i

environ_setup.py

C-Funktionen, die Strings verändern

int gethostname(char *name, size_t namelen);  /* <unistd.h> */

URLS:

%module hostname
%include "cstring.i"

%{
#include <unistd.h>
%}

%cstring_output_maxsize(char *name, size_t namelen);
int gethostname(char *name, size_t namelen);

hostname.i

hostname_setup.py

Strukturen

time_t      time(time_t *tloc);           /* <time.h> */
struct tm * gmtime(const time_t *clock);  /* <time.h> */
char *      asctime(const struct tm *tm); /* <time.h> */

URLs:

%module tm
%include typemaps.i

%{
#include <time.h>
%}

typedef int time_t;

char *asctime(const struct tm *INPUT);
struct tm *gmtime(const time_t *INPUT);
time_t time(time_t *);

tm.i

tm_setup.py

%module tm_verbose
%include typemaps.i

%{
#include <time.h>
%}

struct tm {
        int     tm_sec;         /* seconds after the minute [0-60] */
        int     tm_min;         /* minutes after the hour [0-59] */
        int     tm_hour;        /* hours since midnight [0-23] */
        int     tm_mday;        /* day of the month [1-31] */
        int     tm_mon;         /* months since January [0-11] */
        int     tm_year;        /* years since 1900 */
        int     tm_wday;        /* days since Sunday [0-6] */
        int     tm_yday;        /* days since January 1 [0-365] */
        int     tm_isdst;       /* Daylight Savings Time flag */
        long    tm_gmtoff;      /* offset from UTC in seconds */
        char    *tm_zone;       /* timezone abbreviation */
};

typedef int time_t;

char *asctime(const struct tm *INPUT);
struct tm *gmtime(const time_t *INPUT);
time_t time(time_t *);

tm_verbose.i

tm_verbose_setup.py

C++ Klassen

// person.h -- a C++ class

#ifndef _PERSON_H_
#define _PERSON_H_

#include <string>

class Person {
 public:
  Person(const char *name);
  Person(const Person &anotherOne);
  virtual ~Person();

  const std::string &get_name(void) const;
  void set_name(const char *newname);

 private:
  std::string name_;
};

#endif /* _PERSON_H_ */

person.h

// person.cxx -- a C++ class

#include <iostream>
#include "person.h"

Person::Person(const char *name)
{
  name_ = std::string(name);
}

Person::Person(const Person &anotherOne)
{
  name_ = std::string(anotherOne.get_name());
}

Person::~Person()
{
  std::cout << "Person::~Person() called" << std::endl;
}

const std::string & Person::get_name(void) const
{
  return name_;
}

void Person::set_name(const char *newname)
{
  name_ = std::string(newname);
}

person.cxx

// person_test.cxx -- testing the Person class

#include <iostream>
#include "person.h"

int main(int argc, char *argv[])
{
  Person p("John Doe");
  std::cout << "Name of p: " << p.get_name() << std::endl;
  p.set_name("Jane Doe");
  std::cout << "Name of p: " << p.get_name() << std::endl;

  Person p2(p);
  std::cout << "Name of p2: " << p2.get_name() << std::endl;

  return 0;
}

person_test.cxx

%module person
%include "std_string.i"

%{
#include "person.h"
%}

class Person {
 public:
  Person(const char *name);
  Person(const Person &anotherOne);
  virtual ~Person();

  const std::string &get_name(void) const;
  void set_name(const char *newname);

 private:
  std::string name_;
};

person.i

#!/usr/bin/env python

from distutils.core import setup, Extension

person_module = Extension('_person',
                           sources = ['person_wrap.cxx',
                                      'person.cxx'],
                          )

setup(name        = 'person',
      version     = '0.1',
      author      = 'Farid Hajji',
      description = '''Wrapping C++ class Person''',
      ext_modules = [person_module],
      py_modules  = ["person"],
     )

person_setup.py

Unbekannte Datentypen sind Pointer

#include <unistd.h>

gid_t    getegid(void);
uid_t    geteuid(void);

URLs:

%module uid

gid_t    getegid(void);
uid_t    geteuid(void);

uid_err.i

uid_setup.py

%module uid

typedef  int gid_t;
typedef  int uid_t;

gid_t    getegid(void);
uid_t    geteuid(void);

uid.i

%module fileio

FILE *fopen(char *, char *);
int fclose(FILE *);
unsigned fread(void *ptr, unsigned size, unsigned nobj, FILE *);
unsigned fwrite(void *ptr, unsigned size, unsigned nobj, FILE *);
void *malloc(int nbytes);
void free(void *);

fileio.i

fileio_setup.py

#!/usr/bin/env python
# filecopy.py -- copy binary files with <stdio.h> functions.
#
# Source: SWIG Documentation.

from fileio import *

BLOCKSIZE = 8192

def filecopy(source, target):
    '''Copy file SOURCE to TARGET using fread/fwrite.
    
    The source file MUST contain a multiple of BLOCKSIZE bytes.
    If not, the last block will NOT be copied over!'''
    
    f1     = fopen(source, "r")
    f2     = fopen(target, "w")
    buf    = malloc(BLOCKSIZE)
    
    nrecs = fread(buf, BLOCKSIZE, 1, f1)
    while nrecs > 0:
        fwrite(buf, BLOCKSIZE, 1, f2)
        nrecs  = fread(buf, BLOCKSIZE, 1, f1)
    
    free(buf)
    fclose(f2)
    fclose(f1)

filecopy.py

URLs zum Verständnis von filecopy.py:

Wie geht’s von hier aus weiter?

Low-level Python/C-API

URLs:

Zusammenfassung

URLs: