Embedded Software. Der C Präprozessor. Sichere objektbasierte Entwicklung dank C Präprozessor. Prof. Dr. Nikolaus Wulff

Ähnliche Dokumente
Objektbasierte Entwicklung

Programmieren in C. Macros, Funktionen und modulare Programmstruktur. Prof. Dr. Nikolaus Wulff

Objektbasierte Entwicklung

Java: Vererbung. Teil 3: super()

Javakurs zu Informatik I. Henning Heitkötter

Einführung in die Programmierung

Fakultät Angewandte Informatik Lehrprofessur für Informatik

SEP 114. Design by Contract

Nathan Burgener. Design by Contract. Modul SWE

Zählen von Objekten einer bestimmten Klasse

Objektorientierte Programmierung

Programmierkurs Java

Graphic Coding. Klausur. 9. Februar Kurs A

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Institut für Programmierung und Reaktive Systeme 25. August Programmier-Labor Übungsblatt. int binarysearch(int[] a, int x),

Das erste Programm soll einen Text zum Bildschirm schicken. Es kann mit jedem beliebigen Texteditor erstellt werden.

Client-Server-Beziehungen

Technische Hochschule Georg Agricola WORKSHOP TEIL 3. IKT (Informations- und Kommunikationstechnik) an einer MorseApp erklärt

Erweiterung der Aufgabe. Die Notenberechnung soll nicht nur für einen Schüler, sondern für bis zu 35 Schüler gehen:

Das Typsystem von Scala. L. Piepmeyer: Funktionale Programmierung - Das Typsystem von Scala

Gliederung Grundlagen Schlüsselworte try-catch Fehlerobjekte Fehlerklassen Schlüsselwort finally Schlüsselwort throws selbst erstellte Exceptions

Hochschule Darmstadt Informatik-Praktikum (INF 1) WS 2015/2016 Wirtschaftsingenieur Bachelor 5. Aufgabe Datenstruktur, Dateieingabe und -ausgabe

Große Übung Praktische Informatik 1

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

Einführung in die Programmierung (EPR)

Übung Grundlagen der Programmierung. Übung 03: Schleifen. Testplan Testergebnisse

Einführung in Javadoc

7. Übung zu Algorithmen und Datenstrukturen

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 14/15. Kapitel 11. Fehler und Ausnahmen 1

Downloadfehler in DEHSt-VPSMail. Workaround zum Umgang mit einem Downloadfehler

Programmieren in Java

Java Database Connectivity (JDBC) Walther Rathenau Gewerbeschule 1

Erwin Grüner

Fachgebiet Informationssysteme Prof. Dr.-Ing. N. Fuhr. Programmierung Prof. Dr.-Ing. Nobert Fuhr. Übungsblatt Nr. 6

Dieses Tutorial gibt eine Übersicht der Form Klassen von Struts, welche Besonderheiten und Unterschiede diese aufweisen.

Medea3 Print-Client (m3_print)

Propädeutikum. Dipl.-Inf. Frank Güttler

Melde- und Veröffentlichungsplattform Portal (MVP Portal) Hochladen einer XML-Datei

Einführung in die Java- Programmierung

Studentische Lösung zum Übungsblatt Nr. 7

Informatik Repetitorium SS Volker Jaedicke

Programmieren in C. Die C-Standardbibliothek. Prof. Dr. Nikolaus Wulff

Starten Sie Eclipse: Hier tragen sie Ihr Arbeitsverzeichnis ein. Zu Hause z.b. c:\workspace.

Computeranwendung und Programmierung (CuP)

Rundung und Casting von Zahlen

Tagesprogramm

Programmieren in C. Felder, Schleifen und Fließkommaarithmetik. Prof. Dr. Nikolaus Wulff

Hinweise zur Datensicherung für die - Prüfmittelverwaltung - Inhalt

Einführung in die Programmierung

Einführung in die Programmierung Blockkurs Java

Java Kurs für Anfänger Einheit 4 Klassen und Objekte

Software Engineering. Zur Architektur der Applikation Data Repository. Franz-Josef Elmer, Universität Basel, HS 2015

Dokumentenverwaltung

Themen. Web Service - Clients. Kommunikation zw. Web Services

Oracle: Abstrakte Datentypen:

Javadoc. Programmiermethodik. Eva Zangerle Universität Innsbruck

Testen mit JUnit. Motivation

Scala kann auch faul sein

Elexis-BlueEvidence-Connector

1 Vom Problem zum Programm

Handbuch ECDL 2003 Modul 2: Computermanagement und Dateiverwaltung Der Task-Manager

Klausur Programmieren in C Sommersemester 2007 Dipl. Biol. Franz Schenk 13. April 2007, Uhr Bearbeitungszeit: 105 Minuten

Objektorientierte Programmierung

Installations- und Bedienungsanleitung für Macro Excel_Table Version 10

Design by Contract with JML

Angewandte Mathematik und Programmierung

Übersicht Programmablaufsteuerung

Die Java Stream API. Funktionale Programmierung mit der Stream API des JDK 1.8. Prof. Dr. Nikolaus Wulff

Java 7. Elmar Fuchs Grundlagen Programmierung. 1. Ausgabe, Dezember 2011 JAV7

Programmieren einer Lüftungsanlage mit DDC-Suite Vorlagen Arbeiten mit dem Fupla

Einführung in die Programmierung

Übungsblatt 3: Algorithmen in Java & Grammatiken

Vorkurs C++ Programmierung

Informatik 2 Labor 2 Programmieren in MATLAB Georg Richter

Barcodedatei importieren

Stand: Adressnummern ändern Modulbeschreibung

Anleitung zur Erstellung von Serienbriefen (Word 2003) unter Berücksichtigung von Titeln (wie Dr., Dr. med. usw.)

Informatik Grundlagen, WS04, Seminar 13

Java Reflection. Meta-Programmierung mit der java.lang.reflection API. Prof. Dr. Nikolaus Wulff

Objektorientierte Programmierung. Kapitel 12: Interfaces

Der lokale und verteilte Fall

Anleitung zur Verwendung der VVW-Word-Vorlagen

5. Tutorium zu Programmieren

Microsoft PowerPoint 2013 Folien gemeinsam nutzen

Musterlösung zur Vorlesung Modellbasierte Softwareentwicklung Wintersemester 2014/2015 Übungsblatt 9

Die Programmiersprache C99: Zusammenfassung

Vorgehensweise bei Lastschriftverfahren

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = Euro ergeben.

DLLs (dynamic loaded libraries) mit MingW erstellen

Kontrollstrukturen und Funktionen in C

Hochschule Ravensburg-Weingarten. Technik Wirtschaft Sozialwesen. Projektarbeit

SMS/ MMS Multimedia Center

Praktikum Ingenieurinformatik. Termin 2. Verzweigungen (if-else), printf und scanf, while-schleife

Zwischenablage (Bilder, Texte,...)

Tutorial. Bibliothek AutoGUITest V1.0. Windows-Benutzeroberflächen automatisiert testen. Ausgabe: / 13:51 Seite 1

Grundlagen der Programmierung Prof. H. Mössenböck. 3. Verzweigungen

Klausur WS 2006/07 Programmiersprache Java Objektorientierte Programmierung II 15. März 2007

Um ein solches Dokument zu erzeugen, muss eine Serienbriefvorlage in Word erstellt werden, das auf die von BüroWARE erstellte Datei zugreift.

2A Basistechniken: Weitere Aufgaben

Programmieren für Ingenieure Sommer Ein Rechner. Rechner sind überall. Gerät, das mittels programmierbarer Rechenvorschriften Daten verarbeitet.

Transkript:

Der C Präprozessor Sichere objektbasierte Entwicklung dank C Präprozessor Prof. Dr. Nikolaus Wulff

Shapes kanonische Form Die Aufteilung in Methoden und Attribute erfolgt in zwei Structs XXX_Instance und XXX_Class: typedef struct Shape_Instance_struct* Shape; typedef struct Shape_Class_struct { void (*draw) (Shape ashape); void (*erase) (Shape ashape); void (*moveto) (Shape ashape, int x,int y); } ShapeClass; typedef struct Shape_Instance_struct { ShapeClass *class; int x; int y; } ShapInstance; 2

Rect kanonische Form Die Rect Strukturen sind fast identische Kopien der Shape Strukturen: typedef struct Rect_Instance_struct* Rect; typedef struct Rect_Class_struct { void (*draw) (Shape ashape); void (*erase) (Shape ashape); void (*moveto) (Shape ashape, int x,int y); void (*resize) (Shape ashape, int w,int h); } RectClass; typedef struct Rect_Instance_struct { RectClass *class; int x; int y; int w; int h; } RectInstance; 3

Präprozessoroperatoren Der Präprozessor kann helfen solche generischen Strukturen, die fast identische Kopien sind und sich nur durch Namen entscheiden, zu generieren. Es lassen sich Macros definieren, die als Vorlagen ähnlich den C++ Templates dienen und den Quellcode durch Textersetzung erzeugen. Eine wichtige Rolle spielen hierbei die beiden Präprozessoroperatoren # und ##: # setzt den Parameter in Hochkomma als String ## konkateniert zwei Symbole zu Einem 4

Zeichen Macros #define makestr(x) #x #define concat(x,y) x ## y Der Ausdruck makestr(hello) wird dann zum String "hello" expandiert. Der Ausdruck concat(shape, Class) ergibt das Symbol ShapeClass (nicht als String!). Mit diesen beiden Operatoren lassen sich Quelltexte generieren. 5

C Klassen per Makros Die kanonische Aufteilung in Instanz und Class Strukturen lässt sich per Coding by Convention durch Makros erzwingen und generieren. BEG_DEFINE_CLASS(T) generiert die Class Struktur zum Typen T. BEG_DEFINE_INSTANCE(T) generiert die Instanz Struktur zum Typen T und beinhaltet auch den Zeiger auf die Class Struktur. Ähnlich wie bei C++ Templates oder Java Generics ist T ein Platzhalter für den Typen, z.b. Shape. 6

Shapes per Macro generieren #define BEG_DEFINE_CLASS(T) \ typedef struct T##_Instance_struct* T; \ typedef struct T##_Class_struct { #define END_DEFINE_CLASS(T) \ } T##Class; #define BEG_DEFINE_INSTANCE(T) \ typedef struct T##_Instance_struct { \ T##Class *clazz; #define END_DEFINE_INSTANCE(T) \ } T##Instance; \ extern T new##t(int* args); 7

Shape Attribute + Methoden #define SHAPE_METHODES \ void (*draw) (Shape ashape); \ void (*erase) (Shape ashape); \ void (*moveto) (Shape ashape, int x,int y); #define SHAPE_ATTRIBUTES \ int x; \ int y; 8

Cleveres malloc Mit dem Präprozessor lässt sich auch der malloc Aufruf vereinfachen und typsicher machen: #define alloc(t) (T) malloc( \ sizeof(t ## Instance)) Mit diesem Macro wird immer Code zum passenden ADT erzeugt und die Verwendung von malloc vereinfacht sich von: Rect obj = (Rect) malloc( sizeof(struct Rect_Instance_struct)); zu: Rect obj = alloc(rect); 9

Shape.h mit Macros BEG_DEFINE_CLASS(Shape) SHAPE_METHODES END_DEFINE_CLASS(Shape) BEG_DEFINE_INSTANCE(Shape) SHAPE_ATTRIBUTES END_DEFINE_INSTANCE(Shape) So einfach und aufgeräumt kann eine *.h Datei sein Allerdings sind die Strukturen schwieriger zu verstehen, da die Macros vieles verstecken. Rect.h wird mit genau den selben Macros erzeugt. 10

Rect.h mit Macros #ifndef RECT_H_ #define RECT_H_ #include "Shape.h" BEG_DEFINE_CLASS(Rect) SHAPE_METHODES void (*resize) (Rect r, int w, int h); END_DEFINE_CLASS(Rect) BEG_DEFINE_INSTANCE(Rect) SHAPE_ATTRIBUTES int w; int h; END_DEFINE_INSTANCE(Rect) #define size(r,x,y) R->clazz->resize(R, (x), (y)) #endif /* RECT_H_ */ 11

Rect kanonische Form Diese einfachen Macro Templates generieren zur Compile Zeit die komplette Rect Header Datei: typedef struct Rect_Instance_struct* Rect; typedef struct Rect_Class_struct { void (*draw) (Shape ashape); void (*erase) (Shape ashape); void (*moveto) (Shape ashape, int x,int y); void (*resize) (Shape ashape, int w,int h); } RectClass; typedef struct Rect_Instance_struct { RectClass *class; int x; int y; int w; int h; } RectInstance; 12

Rect.c static void resize(rect obj, int h, int w) { obj->h = h; obj->w = w; } static RectClass rectclass = {draw, erase, moveto, resize }; Shape newrect(int args[]) { Rect obj = alloc(rect); obj->clazz = &rectclass; obj->x = args[0]; obj->y = args[1]; obj->h = args[2]; obj->w = args[3]; return (Shape) obj; } 13

Vererbung automatisieren Eine Vererbungshierarchie lässt sich durch zwei weitere Makros EXTENDS und INSTANCE_OF deklarativ implementieren: BEG_DEFINE_CLASS(Circle) EXTENDS(Shape) METHODS(Circle) END_DEFINE_CLASS(Circle) BEG_DEFINE_INSTANCE(Circle) INSTANCE_OF(Shape) ATTRIBUTES(Circle) END_DEFINE_INSTANCE(Circle) Wie sind EXTENDS und INSTANCE_OF definiert? 14

Kürzer geht es nicht... Wem selbst dies noch zu viel ist, der kann noch das Makro DEFINE_BASE_TYPE für eine Wurzelklasse wie z.b. Shape DEFINE_BASE_TYPE(Shape) und DEFINE_EXTENDED_TYPE für eine Kindklasse wie z.b. Rect definieren: DEFINE_EXTENDED_TYPE(Rect,Shape) Debugen wird schwieriger mit gcc save-temps kann der generierte Code gespeichert werden... 15

Debug Nachrichten Der Präprozessor eignet sich hervorragend um Debugnachrichten auf der Console auszugeben. Den Nachrichten lässt sich eine unterschiedliche Priorität zuordnen und sie werden im Releasemode ganz abschalten. Debugnachrichten lassen sich in Log-Dateien schreiben und später auswerten. Dies hilft, wenn die Anwendung bereits beim Kunden ausgeliefert ist... 16

Vordefinierte Namen in C Es gibt in C neben den geschützten Worten der Sprache einige vordefinierte Namen die zur Übersetzungszeit vom Compiler expandiert werden: LINE : Die Nummer der aktuellen Quellzeile FILE : Der Name der aktuellen Datei DATE : Das Übersetzungsdatum TIME : Die Übersetzungszeit STDC : Konstante für ANSI C Diese vordefinierten Namen lassen sich gut für Debug Macros verwenden... 17

Debug Macro #define DEBUG 1 #ifdef DEBUG #define debug(x) \ printf("debug %s %d %s\n", FILE, LINE,x); #else #define debug(x) #endif static void erase(shape shape) { debug("erase shape"); free(shape); } 18

Fehlerbehandlungen Mit dem Präprozessor lassen sich Strategien für die Fehlerbehandlung erstellen. Für Entwicklungszwecke dient das assert Macro zum Lokalisieren von Fehlern: assert(<conditon>); Wenn die Bedingung 0 == false ist (C kennt keinen boolean) wird eine Exception geworfen und eine Fehlermeldung mit der Zeilennummer in der Quelldatei in stderr geschrieben. 19

Auszug aus dem Assert Macro #define assert(expr) \ ( ASSERT_VOID_CAST ((expr)? 0 : \ ( assert_fail ( STRING(expr), FILE, LINE,\ _ASSERT_FUNCTION), 0))) Dies Macro liest sich so: Wenn expr!=0 mach nichts: (void) 0 Falls expr==0 rufe die Funktion assert_fail mit vier Argumenten: Verwandle expr in einen String (das # Macro hilf da...) Füge Dateinamen und Zeilennummer hinzu Verwende ein Macro, das den aktuellen Funktionennamen expandiert... 20

Design-By-Contract Ende der achtziger Jahre wurde das Programmier Paradigma Design by Contract entwickelt. Es bassiert auf den drei Begriffen: Vorbedingung (PreCondition) Invariante (Invariant) Nachbedingung( PostCondition) Um einen Dienst auszuführen müssen alle Vorbedingungen von Seiten des Aufrufes erfüllt werden. Wenn dem so ist, sichert der Dienst die Nachbedingungen zu. 21

Pre- & PostCondition #include <assert.h> #define precondition(cond, msg) \ if (!(cond)) { \ printf("precondition: %s \n", msg); \ assert(cond); \ } #define postcondition(cond, msg) \ if (!(cond)) { \ printf("postcondition: %s \n", msg); \ assert(cond); \ } Anstatt des assert Macros kann natürlich eine intelligentere Fehlerausgabe erfolgen. 22

Pre/PostCondition Varianten Anstatt assert im Makro zu rufen können die relevanten Informationen direkt gewonnen werden: #define postcondition(cond, msg) \ if (!(cond)) { \ printf("postcondition: %s %s %d %s \n", \ #cond, FILE, LINE, msg); \ abort(); \ } Interessant ist hier die Anwendung des # Operators. Dies gestattet die Bedingung direkt auf der Console als Zeichenkette auszugeben. 23

Anwendung einer PreCondition /** * @param x int has to be >= 0 */ int isqrt(int x) { precondition(x >=0," x <0!"); return (int) sqrt(x); } Das Codefragment zeigt die Anwendung der precondition. Das Argument muss größer 0 sein ansonsten wird eine Fehlermeldung auf der Console ausgegeben. 24

Try-Catch in C C kennt kein echtes Exception Handling wie C++ oder Java. Dennoch lassen sich mit dem Präprozessor Macros definieren die eine Programmierung mit try-catch Blöcken gestatten. Im Internet sind zahlreiche C Macro Bibliotheken zu diesem Thema zu finden. Die Funktionalität und der Umfang sind allerdings recht unterschiedlich. 25

Try Catch Semantik Mit Hilfe von try-catch-finally Blöcken und Exceptions lassen sich Programmflüsse mit Fehlerbedingungen leicht programmieren. Eine Anweisung besteht aus einem try-block, in dem möglicherweise Fehler passieren können. Im anschließenden catch-block erfolgt eine entsprechende Fehlerbehandlung. Der optionale finally-block wird ausgeführt unabhängig davon ob ein Fehler passierte oder nicht. Wird try-catch verwendet macht es Sinn auch die preund postconditions mit Exceptions zu versehen. 26

Try-Catch Verwendung try { if (x == 0) throw(nullpointer); printf("x nicht null\n"); } catch(nullpointer) { printf("x ist null \n"); } printf("nach dem Try Block\n"); Obiges Beispiel zeigt die Anwendung eines einfachen try-catch Blockes. Innerhalb des try Blocks können Fehler geworfen werden, die dann im catch Block gefangen werden. 27

try-catch Beispiel in Java private void executesql(string sql) { Connection con = null; Statement stm = null; try { con = db.getconnection(); stm = con.createstatement(); stm.executeupdate(sql); } catch (SQLException e) { handleerror(e); } finally { releaseresources(con, stm, null); } } Zu sehen ist ein JDBC Zugriff auf eine Datenbank. JDBC definiert SQLExceptions die bei allen Db Operationen passieren können... 28

Simple try catch Nachahmung #define try #define throw(x) goto x #define catch(x) while(0) x: Diese Definitionen sind so ziemlich die einfachste Methode um try-catch Semantik mit C zu emulieren. Diese try-catch Variante funktioniert nur innerhalb einer Methode und nicht übergreifend. Es ist nicht möglich RuntimeExceptions zu fangen wie es in C++ mit catch(...) möglich ist. Diese Pseudo Implementierung ist sicherlich nicht der Weisheit letzter Schluss... 29

Weitere try-catch Macros Im Internet sind zahlreiche Macro Bibliotheken zu finden, die in ihrem Leistungsvermögen an die echten try catch Blöcke der C++ Semantik herankommen: http://home.rochester.rr.com/bigbyofrocny/gef/ http://cexcept.sourceforge.net/ Es lohnt sich einen Blick in die cexcept Beispiele zu werfen. Es müssen lediglich die dortigen Macros verwendet werden, um try-catch Semantik Methoden übergreifend verwenden zu können. 30

PreCondition mit Exceptions Mit Hilfe von try-catch und Exceptions kann auch das Design by Contract Konzept viel sauberer implementiert werden: #define precondition(cond, msg) \ if (!(cond)) { \ printf("postcondition: %s %s %d %s \n", \ #cond, FILE, LINE, msg); \ throw Exception(#cond, msg); \ } 31