Systemnahe Programmierung in C/C++



Ähnliche Dokumente
Zählen von Objekten einer bestimmten Klasse

Vorkurs C++ Programmierung

Tutorium Rechnerorganisation

Dr. Monika Meiler. Inhalt

Java Virtual Machine (JVM) Bytecode

Einführung in die Programmierung Laborübung bei Korcan Y. Kirkici. 12.Übung bis

Die Programmiersprache C99: Zusammenfassung

Modellierung und Programmierung 1

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

Grundlagen von Python

Fakultät Angewandte Informatik Lehrprofessur für Informatik

Objektorientierte Programmierung

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

4D Server v12 64-bit Version BETA VERSION

Deklarationen in C. Prof. Dr. Margarita Esponda

Einführung in die C-Programmierung

Unterprogramme. Funktionen. Bedeutung von Funktionen in C++ Definition einer Funktion. Definition einer Prozedur

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

Praxisorientierte Einführung in C++ Lektion: "Die Compiler-Chain (Vom Quellcode zum ausführbaren Programm)"

2. Programmierung in C

OPERATIONEN AUF EINER DATENBANK

DOKUMENTATION VOGELZUCHT 2015 PLUS

Kompilieren und Linken

Datentypen: Enum, Array, Struct, Union

Grundlagen der Informatik. Prof. Dr. Stefan Enderle NTA Isny

TIMI: Technische Informatik für Medieninformatiker

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

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

Einführung in die Programmierung

Objektbasierte Entwicklung

Zwischenablage (Bilder, Texte,...)

Einführung in die C++ Programmierung für Ingenieure

PROGRAMMIEREN MIT C. }, wird kompiliert mit dem Befehl. (-o steht für output) und ausgeführt mit dem Befehl

Einführung in die Programmierung

Windows 10. Vortrag am Fleckenherbst Bürgertreff Neuhausen.

Einführung in die Java- Programmierung

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

Virtueller Seminarordner Anleitung für die Dozentinnen und Dozenten

SafeRun-Modus: Die Sichere Umgebung für die Ausführung von Programmen

Übungspaket 31 Entwicklung eines einfachen Kellerspeiches (Stacks)

Programmierung mit C Zeiger

C A R L V O N O S S I E T Z K Y. Boost C++ Libraries. Johannes Diemke. Department of Computer Science Learning and Cognitive Systems

Übung: Verwendung von Java-Threads

Tapps mit XP-Mode unter Windows 7 64 bit (V2.0)

Fachbericht zum Thema: Anforderungen an ein Datenbanksystem

Ein Blick voraus. des Autors von C++: Bjarne Stroustrup Conrad Kobsch

Grundlagen. Kapitel 1

0. Einführung. C und C++ (CPP)

C++ Grundlagen. ++ bedeutet Erweiterung zum Ansi C Standard. Hier wird eine Funktion eingeleitet

Qt-Projekte mit Visual Studio 2005

5 DATEN Variablen. Variablen können beliebige Werte zugewiesen und im Gegensatz zu

Tipps und Tricks zu Netop Vision und Vision Pro

LEHRSTUHL FÜR DATENBANKEN

Anleitung zur Einrichtung einer ODBC Verbindung zu den Übungsdatenbanken

Einführung in PHP. (mit Aufgaben)

Installationsanleitung Maschinenkonfiguration und PP s. Release: VISI 21 Autor: Anja Gerlach Datum: 18. Dezember 2012 Update: 18.

1 Voraussetzungen für Einsatz des FRITZ! LAN Assistenten

Prozessarchitektur einer Oracle-Instanz

Ordner Berechtigung vergeben Zugriffsrechte unter Windows einrichten

Nuetzlicher Kleinkram

Dynamische Speicherverwaltung

Die Programmiersprache C

Installation und Inbetriebnahme von SolidWorks

Felder, Rückblick Mehrdimensionale Felder. Programmieren in C

Softwaretests in Visual Studio 2010 Ultimate Vergleich mit Java-Testwerkzeugen. Alexander Schunk Marcel Teuber Henry Trobisch

Programmentwicklung mit C++ (unter Unix/Linux)

Übungen zu Systemprogrammierung 1 (SP1)

Java Entwicklung für Embedded Devices Best & Worst Practices!

Übung 9 - Lösungsvorschlag

Übung - Freigabe eines Ordners und Zuordnung eines Netzwerlaufwerks in Windows XP

2. Word-Dokumente verwalten

Applet Firewall und Freigabe der Objekte

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

3 ORDNER UND DATEIEN. 3.1 Ordner

Übungen zu Systemprogrammierung 1

Einführung in die technische Informatik

1 Dokumentenmanagement

Programmierparadigmen. Programmierparadigmen. Imperatives vs. objektorientiertes Programmieren. Programmierparadigmen. Agenda für heute, 4.

Anleitung zum Arbeiten mit Microsoft Visual Studio 2008 im Softwarepraktikum ET/IT

Kurzanleitung. Nutzung des Online Office von 1&1. Zusammengestellt:

Tutorial: Wie kann ich Dokumente verwalten?

Step by Step Webserver unter Windows Server von Christian Bartl

Pass by Value Pass by Reference Defaults, Overloading, variable Parameteranzahl

Proseminar C-Programmierung. Strukturen. Von Marcel Lebek

Leitfaden zur Installation von Bitbyters.WinShutdown

AGROPLUS Buchhaltung. Daten-Server und Sicherheitskopie. Version vom b

Er musste so eingerichtet werden, dass das D-Laufwerk auf das E-Laufwerk gespiegelt

Java Kurs für Anfänger Einheit 5 Methoden

Archiv - Berechtigungen

Professionelle Seminare im Bereich MS-Office

Einführung in die Programmierung

Grundbegriffe der Informatik

Zugriff auf die Modul-EEPROMs

Volksbank Oelde-Ennigerloh-Neubeckum eg

Objektorientierte Programmierung. Kapitel 12: Interfaces

Die Programmiersprache Java. Dr. Wolfgang Süß Thorsten Schlachter

Erweiterung AE WWS Lite Win: AES Security Verschlüsselung

Programmierkurs Java

6.1.2 Beispiel 118: Kennwort eines Benutzers ändern

Ziel, Inhalt. Programmieren in C++ Wir lernen wie man Funktionen oder Klassen einmal schreibt, so dass sie für verschiedene Datentypen verwendbar sind

Transkript:

Systemnahe Programmierung in C/C++ Compiler, Zeiger, Speicherverwaltung, Macros Knut Stolze stolze@informatik.uni-jena.de Lehrstuhl für Datenbanken und Informationssysteme Fakultät für Mathematik und Informatik 2006 10 18 Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 1 / 62

Agenda 1 Einführung 2 Compiler Compile-Prozess Compiler 3 Zeiger & Arrays Grundlagen Arrays 4 Speicherverwaltung Arten von Speicher Funktionen Tipps & Hinweise 5 Präprozessor & Macros 6 Aufgaben Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 2 / 62

Outline 1 Einführung 2 Compiler Compile-Prozess Compiler 3 Zeiger & Arrays Grundlagen Arrays 4 Speicherverwaltung Arten von Speicher Funktionen Tipps & Hinweise 5 Präprozessor & Macros 6 Aufgaben Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 3 / 62

Überblick Ursprünglich von Dennis Ritchie (Bell Laboratories) für die Entwicklung von UNIX in den 1970ern entworfen Hatte sehr starken Einfluss auf andere Programmiersprachen (C++, Java) Sehr systemnah Bietet jedoch genügend Abstraktion gegenüber Assembler Sehr weites Einsatzgebiet Die Programmiersprache für Systemprogrammierung Wird (wurde) auch für Anwendungsentwicklung eingesetzt Gut portierbar Üblicherweise die erste High-Level-Sprache für neue Computer Abhängig von Problem nicht immer die beste Wahl Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 4 / 62

Überblick Ursprünglich von Dennis Ritchie (Bell Laboratories) für die Entwicklung von UNIX in den 1970ern entworfen Hatte sehr starken Einfluss auf andere Programmiersprachen (C++, Java) Sehr systemnah Bietet jedoch genügend Abstraktion gegenüber Assembler Sehr weites Einsatzgebiet Die Programmiersprache für Systemprogrammierung Wird (wurde) auch für Anwendungsentwicklung eingesetzt Gut portierbar Üblicherweise die erste High-Level-Sprache für neue Computer Abhängig von Problem nicht immer die beste Wahl Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 4 / 62

Eigenschaften von C Systemnähe erlaubt einfache Übersetzung (Compilation) Gute Optimierungsmöglichkeiten; nur wenige Machineninstruktionen für Sprachelemente Keine komplexe Laufzeitumgebung Bietet Low-level Zugang zu Speicher, Devices,... Einfach und ausdrucksstark, jedoch etwas kryptisch Kompakter Code C code kann 20-50% schneller sein als Programme in High-Level Programmiersprachen; allerdings ist Programmierung oft aufwändiger Meist sind nur 10% des Codes performance-kritisch Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 5 / 62

C in dieser Lehrveranstaltung Nicht die beste Programmiersprache für Einsteiger ABER: Jeder Informatikstudent sollte ein gutes Verständnis dafür haben, was auf Systemebene passiert. Wir decken keine Grundlagen der Programmierung ab! Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 6 / 62

C in dieser Lehrveranstaltung Nicht die beste Programmiersprache für Einsteiger ABER: Jeder Informatikstudent sollte ein gutes Verständnis dafür haben, was auf Systemebene passiert. Wir decken keine Grundlagen der Programmierung ab! Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 6 / 62

C in dieser Lehrveranstaltung Nicht die beste Programmiersprache für Einsteiger ABER: Jeder Informatikstudent sollte ein gutes Verständnis dafür haben, was auf Systemebene passiert. Wir decken keine Grundlagen der Programmierung ab! Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 6 / 62

Outline 1 Einführung 2 Compiler Compile-Prozess Compiler 3 Zeiger & Arrays Grundlagen Arrays 4 Speicherverwaltung Arten von Speicher Funktionen Tipps & Hinweise 5 Präprozessor & Macros 6 Aufgaben Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 7 / 62

Warum Compiler? C (und C++) sind keine interpretierten Sprachen Quellcode wird vor dem Ausführen in Maschinencode übersetzt Maschinencode ist abhängig vom jeweiligen Prozessor bzw. dessen Architektur und Befehlssatz Compiler übersetzt Quellcode in Maschinencode Quellcode üblicherweise strukturiert in mehrere Dateien Bessere Modularisierung Trennung von Implementierung und Schnittstellen (Header) Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 8 / 62

Warum Compiler? C (und C++) sind keine interpretierten Sprachen Quellcode wird vor dem Ausführen in Maschinencode übersetzt Maschinencode ist abhängig vom jeweiligen Prozessor bzw. dessen Architektur und Befehlssatz Compiler übersetzt Quellcode in Maschinencode Quellcode üblicherweise strukturiert in mehrere Dateien Bessere Modularisierung Trennung von Implementierung und Schnittstellen (Header) Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 8 / 62

Warum Compiler? C (und C++) sind keine interpretierten Sprachen Quellcode wird vor dem Ausführen in Maschinencode übersetzt Maschinencode ist abhängig vom jeweiligen Prozessor bzw. dessen Architektur und Befehlssatz Compiler übersetzt Quellcode in Maschinencode Quellcode üblicherweise strukturiert in mehrere Dateien Bessere Modularisierung Trennung von Implementierung und Schnittstellen (Header) Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 8 / 62

Warum Compiler? C (und C++) sind keine interpretierten Sprachen Quellcode wird vor dem Ausführen in Maschinencode übersetzt Maschinencode ist abhängig vom jeweiligen Prozessor bzw. dessen Architektur und Befehlssatz Compiler übersetzt Quellcode in Maschinencode Quellcode üblicherweise strukturiert in mehrere Dateien Bessere Modularisierung Trennung von Implementierung und Schnittstellen (Header) Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 8 / 62

Compile-Prozess.c pre processor.i compiler.s.h.h.h assembler <exe>.so linker.o archiver.a.so.a Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 9 / 62

Schritte (1) 1 Precompiler Bindet Header-Dateien ein Löst Macros auf In Compiler integriert Precompile-Ausgabe mit Option -E erzeugen: gcc -E file.c Für Debugging-Zwecke 2 Compiler Übersetzt C Code in Assembler Code In Compiler integriert Assembler-Ausgabe mit Option -S erzeugen: gcc -S file.c Für Debugging-Zwecke 3 Assembler Übersetzt Assembler Code in Maschinencode (Objektcode) In Compiler integriert Objektcode mit Option -c erzeugen: gcc -c file.c Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 10 / 62

Schritte (1) 1 Precompiler Bindet Header-Dateien ein Löst Macros auf In Compiler integriert Precompile-Ausgabe mit Option -E erzeugen: gcc -E file.c Für Debugging-Zwecke 2 Compiler Übersetzt C Code in Assembler Code In Compiler integriert Assembler-Ausgabe mit Option -S erzeugen: gcc -S file.c Für Debugging-Zwecke 3 Assembler Übersetzt Assembler Code in Maschinencode (Objektcode) In Compiler integriert Objektcode mit Option -c erzeugen: gcc -c file.c Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 10 / 62

Schritte (1) 1 Precompiler Bindet Header-Dateien ein Löst Macros auf In Compiler integriert Precompile-Ausgabe mit Option -E erzeugen: gcc -E file.c Für Debugging-Zwecke 2 Compiler Übersetzt C Code in Assembler Code In Compiler integriert Assembler-Ausgabe mit Option -S erzeugen: gcc -S file.c Für Debugging-Zwecke 3 Assembler Übersetzt Assembler Code in Maschinencode (Objektcode) In Compiler integriert Objektcode mit Option -c erzeugen: gcc -c file.c Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 10 / 62

Schritte (2) 4 Linker Verknüpft mehrere Dateien mit Objektcode (.o), Archive (.a) und Shared Libraries (.so) zu Ausführbarem Programm, oder Shared Library Symbole werden verifiziert und ggf. aufgelöst Wird oft über Compiler aufgerufen: gcc file1.o file2.o archive.a -o prog Kann auch direkt aufgerufen werden (üblicherweise Programmname ld) 5 Archivierer Kombiniert mehrere Dateien mit Objektcode (.o) in ein Archiv (.a) Wird über separates Programm names ar initiiert ar c archive.a file1.o file2.o Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 11 / 62

Schritte (2) 4 Linker Verknüpft mehrere Dateien mit Objektcode (.o), Archive (.a) und Shared Libraries (.so) zu Ausführbarem Programm, oder Shared Library Symbole werden verifiziert und ggf. aufgelöst Wird oft über Compiler aufgerufen: gcc file1.o file2.o archive.a -o prog Kann auch direkt aufgerufen werden (üblicherweise Programmname ld) 5 Archivierer Kombiniert mehrere Dateien mit Objektcode (.o) in ein Archiv (.a) Wird über separates Programm names ar initiiert ar c archive.a file1.o file2.o Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 11 / 62

Wahl des Compilers Compiler sind plattformabhängig, z. B. Linux: gcc, icc (Intel) AIX: gcc, xlc (Visual Age C Compiler von IBM) HPUX: gcc, acc Windows: cl, gcc, icc Lizenzkosten! gcc auf vielen Plattformen verfügbar Herstellerspezifischer Compiler kann bessere Ergebnisse liefern Unterschiede i. A. nur im High-Performance-Bereich relevant, z. B. bei Betriebssystemen oder DBMS Feine Unterschiede bei Erkennung von Programmierfehlern/-warnungen Wenn möglich, Quellcode mit mehreren Compilern übersetzen und Testen Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 12 / 62

Compileroptionen Differieren von Compiler zu Compiler!! Typischerweise: -I<dir> Verzeichnisse, in denen Header-Dateien gesucht werden -L<dir> Verzeichnisse, in denen Bibliotheken gesucht werden -l<lib> Bibliothek <lib> wird beim Linken engebunden -W<warn> Warnungen aktivieren, z. B. -Wall -g Debugging-Symbole in Objektdateien hinterlegen -D<macro> Definiere Macro <macro> -O<level> Optimierung und Optimierungslevel einschalten, z. B. -O2 -o<file> Ergebnis in Datei <file> schreiben -f<option> Generelle Compiler-Option einschalten, z. B. -ffast-math Handbuch & man-pages des Compilers konsultieren Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 13 / 62

Compilerfehler Compiler, Linker, Archivierer sind auch nur Programme Enthalten potentiell auch Fehler Fehler sehr schwer zu finden Unterschiede im Verhalten zwischen Debug- und optimierten Objektcode möglich Zwischenergebnisse können in Prozessorregistern gehalten oder in den Hauptspeicher zurückgeschrieben werden Register haben höhere Genauigkeit als 64-bit double-werte Rightarrow Unterschiedliche Rundung von Ergebnissen Hohe Optimierungslevel beim gcc können semantische Abweichungen verursachen, z. B. Code mit Seiteneffekten Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 14 / 62

Outline 1 Einführung 2 Compiler Compile-Prozess Compiler 3 Zeiger & Arrays Grundlagen Arrays 4 Speicherverwaltung Arten von Speicher Funktionen Tipps & Hinweise 5 Präprozessor & Macros 6 Aufgaben Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 15 / 62

Zeiger Ursprünge in Prozessorarchitektur Indirekte Adressierung Wert eines Zeiger (Pointer) verweist auf anderen Wert Zeiger = Adresse im Hauptspeicher Durch * bei Deklaration gekennzeichnet * dereferenziert Zeiger Gibt Wert zurück, der an Adresse steht, auf die Zeiger verweist Adress-Operator & ermittelt Addresse einer Variablen, die Zeiger zugewiesen werden kann Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 16 / 62

Zeiger Ursprünge in Prozessorarchitektur Indirekte Adressierung Wert eines Zeiger (Pointer) verweist auf anderen Wert Zeiger = Adresse im Hauptspeicher Durch * bei Deklaration gekennzeichnet * dereferenziert Zeiger Gibt Wert zurück, der an Adresse steht, auf die Zeiger verweist Adress-Operator & ermittelt Addresse einer Variablen, die Zeiger zugewiesen werden kann Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 16 / 62

Zeiger Ursprünge in Prozessorarchitektur Indirekte Adressierung Wert eines Zeiger (Pointer) verweist auf anderen Wert Zeiger = Adresse im Hauptspeicher Durch * bei Deklaration gekennzeichnet * dereferenziert Zeiger Gibt Wert zurück, der an Adresse steht, auf die Zeiger verweist Adress-Operator & ermittelt Addresse einer Variablen, die Zeiger zugewiesen werden kann Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 16 / 62

Zeiger Ursprünge in Prozessorarchitektur Indirekte Adressierung Wert eines Zeiger (Pointer) verweist auf anderen Wert Zeiger = Adresse im Hauptspeicher Durch * bei Deklaration gekennzeichnet * dereferenziert Zeiger Gibt Wert zurück, der an Adresse steht, auf die Zeiger verweist Adress-Operator & ermittelt Addresse einer Variablen, die Zeiger zugewiesen werden kann Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 16 / 62

Zeiger Beispiel char c = a ; char *p = &c; char n = *p; p hält Adresse, an der Wert von c ( a ) gespeichert ist p: &c c: a Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 17 / 62

Zeiger auf Zeiger Referenzierter Wert kann wiederum Zeiger sein char c = a ; char *p = &c; char **pp = &&p; char n = **pp; pp: &p = &&p p: &c c: a Kann bis zu beliebiger Tiefe weiter geschachtelt werden Bei mehr als 2 Indirektionen sehr schlecht zu durchschauen Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 18 / 62

Grundlagen Zeigerarithmetik Ergebnis von malloc zeigt auf erstes Element des spezifizierten Datentyps (nach Cast) int *ptr = (int *)malloc(n * sizeof(int)); ptr zeigt auf int-wert Wie auf nachfolgende n 1 Werte zugreifen? Zeiger weiterrücken Zeigerarithmetik arbeitet grundsätzlich auf zu Grunde liegenden Datentyp ptr = ptr + 1; Zeiger zeigt auf nächsten int-wert nicht auf das nächste Byte! Bei 32-bit Integers wird Zeiger um 4 Bytes weitergerückt Zeiger sind keine Zahlen! Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 19 / 62

Grundlagen Zeigerarithmetik Ergebnis von malloc zeigt auf erstes Element des spezifizierten Datentyps (nach Cast) int *ptr = (int *)malloc(n * sizeof(int)); ptr zeigt auf int-wert Wie auf nachfolgende n 1 Werte zugreifen? Zeiger weiterrücken Zeigerarithmetik arbeitet grundsätzlich auf zu Grunde liegenden Datentyp ptr = ptr + 1; Zeiger zeigt auf nächsten int-wert nicht auf das nächste Byte! Bei 32-bit Integers wird Zeiger um 4 Bytes weitergerückt Zeiger sind keine Zahlen! Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 19 / 62

Grundlagen Zeigerarithmetik Ergebnis von malloc zeigt auf erstes Element des spezifizierten Datentyps (nach Cast) int *ptr = (int *)malloc(n * sizeof(int)); ptr zeigt auf int-wert Wie auf nachfolgende n 1 Werte zugreifen? Zeiger weiterrücken Zeigerarithmetik arbeitet grundsätzlich auf zu Grunde liegenden Datentyp ptr = ptr + 1; Zeiger zeigt auf nächsten int-wert nicht auf das nächste Byte! Bei 32-bit Integers wird Zeiger um 4 Bytes weitergerückt Zeiger sind keine Zahlen! Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 19 / 62

Zeigerarithmetik Beispiel p = (int *)malloc(5 * sizeof(int)): 1 2 3 4 5 p p+1 p+2 p+3 p+4 Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 20 / 62

Arrays Arrays sind meist identisch mit Zeigern Ausname: sizeof Operator sizeof(int *) == 4 sizeof(int[5]) == 20 Länge des Arrays nur bei Allokation relevant Wird beim Zugriff zur Laufzeit nicht geprüft Können bei Allokation auf dem Stack initialisiert werden char arr1[5] = { a, b, c, d }; int arr2[10] = { 1, 2, 3 }; Zu viele Elemente beim Initialisieren nicht erlaubt Zu wenige Elemente Rest mit 0 aufgefüllt Initialisierungsliste bestimmt Arraygröße wenn nicht explizit angegeben Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 21 / 62

Arrays Arrays sind meist identisch mit Zeigern Ausname: sizeof Operator sizeof(int *) == 4 sizeof(int[5]) == 20 Länge des Arrays nur bei Allokation relevant Wird beim Zugriff zur Laufzeit nicht geprüft Können bei Allokation auf dem Stack initialisiert werden char arr1[5] = { a, b, c, d }; int arr2[10] = { 1, 2, 3 }; Zu viele Elemente beim Initialisieren nicht erlaubt Zu wenige Elemente Rest mit 0 aufgefüllt Initialisierungsliste bestimmt Arraygröße wenn nicht explizit angegeben Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 21 / 62

Arrays Arrays sind meist identisch mit Zeigern Ausname: sizeof Operator sizeof(int *) == 4 sizeof(int[5]) == 20 Länge des Arrays nur bei Allokation relevant Wird beim Zugriff zur Laufzeit nicht geprüft Können bei Allokation auf dem Stack initialisiert werden char arr1[5] = { a, b, c, d }; int arr2[10] = { 1, 2, 3 }; Zu viele Elemente beim Initialisieren nicht erlaubt Zu wenige Elemente Rest mit 0 aufgefüllt Initialisierungsliste bestimmt Arraygröße wenn nicht explizit angegeben Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 21 / 62

Array vs. Zeiger Beispiel a[5]: 1 2 3 4 5 p = a = &a[0] p+1 = a+1 = &a[1] p+2 = a+2 = &a[2] p+3 = a+3 = &a[3] p+4 = a+4 = &a[4] Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 22 / 62

Outline 1 Einführung 2 Compiler Compile-Prozess Compiler 3 Zeiger & Arrays Grundlagen Arrays 4 Speicherverwaltung Arten von Speicher Funktionen Tipps & Hinweise 5 Präprozessor & Macros 6 Aufgaben Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 23 / 62

Einführung Hauptspeicher (RAM) ist (meist) linear und ein zusammenhängender Bereich Muss unterteilt/strukturiert werden Nicht-linearer Speicher (NUMA) wird vom Betriebssystem verwaltet Alle Informationen (Daten und Programme) müssen im Hauptspeicher abgelegt werden Virtualisierung von Speicher Erweiterung des physisch vorhandenen Hauptspeichers um Paging/Swap Space Betriebssystem kümmert sich um Paging/Swapping Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 24 / 62

Einführung Hauptspeicher (RAM) ist (meist) linear und ein zusammenhängender Bereich Muss unterteilt/strukturiert werden Nicht-linearer Speicher (NUMA) wird vom Betriebssystem verwaltet Alle Informationen (Daten und Programme) müssen im Hauptspeicher abgelegt werden Virtualisierung von Speicher Erweiterung des physisch vorhandenen Hauptspeichers um Paging/Swap Space Betriebssystem kümmert sich um Paging/Swapping Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 24 / 62

Einführung Hauptspeicher (RAM) ist (meist) linear und ein zusammenhängender Bereich Muss unterteilt/strukturiert werden Nicht-linearer Speicher (NUMA) wird vom Betriebssystem verwaltet Alle Informationen (Daten und Programme) müssen im Hauptspeicher abgelegt werden Virtualisierung von Speicher Erweiterung des physisch vorhandenen Hauptspeichers um Paging/Swap Space Betriebssystem kümmert sich um Paging/Swapping Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 24 / 62

Speicherverwaltung Programme können parallel laufen Jedes Programm ist unabhängig von anderen Jede Variable in einem Programm muss in einem zuvor reservierten Speicherbereich abgelegt werden! Speicher muss Programm zugeteilt bzw. von diesem reserviert werden prog2 data2 shared memory data1 prog1 0x0000 0xFFFF Betriebssystem verwaltet, welches Programm welchen Speicherbereich verwendet Speicher wird in Seiten aufgeteilt Indirekte Verwaltung der Seiten Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 25 / 62

Speicherverwaltung Programme können parallel laufen Jedes Programm ist unabhängig von anderen Jede Variable in einem Programm muss in einem zuvor reservierten Speicherbereich abgelegt werden! Speicher muss Programm zugeteilt bzw. von diesem reserviert werden prog2 data2 shared memory data1 prog1 0x0000 0xFFFF Betriebssystem verwaltet, welches Programm welchen Speicherbereich verwendet Speicher wird in Seiten aufgeteilt Indirekte Verwaltung der Seiten Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 25 / 62

Arten von Speicher in einem Programm 1 Statischer Speicher Globale Variablen Statische Variablen in Funktionen Laufzeitumgebung, z. B. Ein-/Ausgabestreams (stdin/stdout/stderr) Speicher direkt beim Programmstart allokiert; existiert bis zum Programmende 2 Automatischer Speicher Funktionsargumente & lokale Variablen Stack 3 Dynamischer Speicher Dynamisch allokierte und freigegebene Speicherbereiche Heap 4 Konstanter Speicher Nicht-änderbare Daten (Konstanten) Data segment im Maschinencode Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 26 / 62

Arten von Speicher in einem Programm 1 Statischer Speicher Globale Variablen Statische Variablen in Funktionen Laufzeitumgebung, z. B. Ein-/Ausgabestreams (stdin/stdout/stderr) Speicher direkt beim Programmstart allokiert; existiert bis zum Programmende 2 Automatischer Speicher Funktionsargumente & lokale Variablen Stack 3 Dynamischer Speicher Dynamisch allokierte und freigegebene Speicherbereiche Heap 4 Konstanter Speicher Nicht-änderbare Daten (Konstanten) Data segment im Maschinencode Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 26 / 62

Arten von Speicher in einem Programm 1 Statischer Speicher Globale Variablen Statische Variablen in Funktionen Laufzeitumgebung, z. B. Ein-/Ausgabestreams (stdin/stdout/stderr) Speicher direkt beim Programmstart allokiert; existiert bis zum Programmende 2 Automatischer Speicher Funktionsargumente & lokale Variablen Stack 3 Dynamischer Speicher Dynamisch allokierte und freigegebene Speicherbereiche Heap 4 Konstanter Speicher Nicht-änderbare Daten (Konstanten) Data segment im Maschinencode Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 26 / 62

Arten von Speicher in einem Programm 1 Statischer Speicher Globale Variablen Statische Variablen in Funktionen Laufzeitumgebung, z. B. Ein-/Ausgabestreams (stdin/stdout/stderr) Speicher direkt beim Programmstart allokiert; existiert bis zum Programmende 2 Automatischer Speicher Funktionsargumente & lokale Variablen Stack 3 Dynamischer Speicher Dynamisch allokierte und freigegebene Speicherbereiche Heap 4 Konstanter Speicher Nicht-änderbare Daten (Konstanten) Data segment im Maschinencode Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 26 / 62

Stack vs. Heap Heap Stack Gesamter Speicher, der einem Programm zur Verfügung steht Stack und Heap teilen sich gesamten zur Verfügung stehenden Speicher Pro Prozess Bereiche wachsen gegeneinander Heap: dynamisch benötigter Speicher Stack: statisch verwendeter Speicher Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 27 / 62

Stack Für alle statischen Informationen während des Programmablaufs Wird zur Laufzeit allokiert nicht beim Starten! Aufrufinformationen Welche Funktion wurde von wo aufgerufen Parameter der aufgerufenen Funktion Rücksprungadresse Lokale Variablen Lokale Variablen in der Funktion Z. B. Genügend Speicher für 50 int Werte: int a[50] Automatisch beim Eintritt in den Block/Funktion allokiert Automatisch beim Verlassen des Blocks/der Funktion aufgeräumt, d. h. der Speicher wird wieder freigegeben Jeder Block/Funktion hat eigene Kopie (reentrant) des Stacks Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 28 / 62

Stack Vergleich Andere Programmiersprachen C++: Destruktor von Objekten wird aufgerufen + Speicher wird freigegeben Java: Nur dynamischer Speicher für Objekte Lediglich Referenzen auf dem Stack Reference count wird reduziert Garbage Collector räumt Objekte selbst auf Allokation auf dem Stack ist schneller/performanter als Heap Stack kann nicht fragmentieren Keine Suche nach freien Speicher nötig Speicher auf dem Stack ist nicht initialisiert. Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 29 / 62

Stack Vergleich Andere Programmiersprachen C++: Destruktor von Objekten wird aufgerufen + Speicher wird freigegeben Java: Nur dynamischer Speicher für Objekte Lediglich Referenzen auf dem Stack Reference count wird reduziert Garbage Collector räumt Objekte selbst auf Allokation auf dem Stack ist schneller/performanter als Heap Stack kann nicht fragmentieren Keine Suche nach freien Speicher nötig Speicher auf dem Stack ist nicht initialisiert. Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 29 / 62

Stack Vergleich Andere Programmiersprachen C++: Destruktor von Objekten wird aufgerufen + Speicher wird freigegeben Java: Nur dynamischer Speicher für Objekte Lediglich Referenzen auf dem Stack Reference count wird reduziert Garbage Collector räumt Objekte selbst auf Allokation auf dem Stack ist schneller/performanter als Heap Stack kann nicht fragmentieren Keine Suche nach freien Speicher nötig Speicher auf dem Stack ist nicht initialisiert. Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 29 / 62

Heap Für dynamisch allokierten Speicher Größe kann nach Bedarf variieren Funktion malloc fordert Speicherblock an Passender Block muss im Heap gesucht, reserviert und zurückgegeben werden Funktion free gibt zuvor angeforderten Speicherblock wieder frei Speicher des Heaps kann fragmentieren Heap und einzelne Speicherblöcke üblicherweise vom Betriebssystem (operating system) verwaltet Manche Programme verwendenen eigene Speicherverwaltung Bessere Strukturierung (memory pools) Gezielte Kontrolle des gesamten Speichers möglich Speicher auf dem Heap ist nicht initialisiert. Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 30 / 62

Heap Für dynamisch allokierten Speicher Größe kann nach Bedarf variieren Funktion malloc fordert Speicherblock an Passender Block muss im Heap gesucht, reserviert und zurückgegeben werden Funktion free gibt zuvor angeforderten Speicherblock wieder frei Speicher des Heaps kann fragmentieren Heap und einzelne Speicherblöcke üblicherweise vom Betriebssystem (operating system) verwaltet Manche Programme verwendenen eigene Speicherverwaltung Bessere Strukturierung (memory pools) Gezielte Kontrolle des gesamten Speichers möglich Speicher auf dem Heap ist nicht initialisiert. Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 30 / 62

Heap Für dynamisch allokierten Speicher Größe kann nach Bedarf variieren Funktion malloc fordert Speicherblock an Passender Block muss im Heap gesucht, reserviert und zurückgegeben werden Funktion free gibt zuvor angeforderten Speicherblock wieder frei Speicher des Heaps kann fragmentieren Heap und einzelne Speicherblöcke üblicherweise vom Betriebssystem (operating system) verwaltet Manche Programme verwendenen eigene Speicherverwaltung Bessere Strukturierung (memory pools) Gezielte Kontrolle des gesamten Speichers möglich Speicher auf dem Heap ist nicht initialisiert. Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 30 / 62

Heap Für dynamisch allokierten Speicher Größe kann nach Bedarf variieren Funktion malloc fordert Speicherblock an Passender Block muss im Heap gesucht, reserviert und zurückgegeben werden Funktion free gibt zuvor angeforderten Speicherblock wieder frei Speicher des Heaps kann fragmentieren Heap und einzelne Speicherblöcke üblicherweise vom Betriebssystem (operating system) verwaltet Manche Programme verwendenen eigene Speicherverwaltung Bessere Strukturierung (memory pools) Gezielte Kontrolle des gesamten Speichers möglich Speicher auf dem Heap ist nicht initialisiert. Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 30 / 62

Allokation Fordere einen Speicherblock vom Heap an void *ptr = malloc(size); ptr ist ein Zeiger auf den Beginn des Speicherblocks Ein Zeiger ist eine Adresse im Hauptspeicher size ist die Größe des Blocks in Anzahl von Bytes Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 31 / 62

Allokation Fordere einen Speicherblock vom Heap an void *ptr = malloc(size); ptr ist ein Zeiger auf den Beginn des Speicherblocks Ein Zeiger ist eine Adresse im Hauptspeicher size ist die Größe des Blocks in Anzahl von Bytes Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 31 / 62

Allokation Fordere einen Speicherblock vom Heap an void *ptr = malloc(size); ptr ist ein Zeiger auf den Beginn des Speicherblocks Ein Zeiger ist eine Adresse im Hauptspeicher size ist die Größe des Blocks in Anzahl von Bytes ptr (0x4005) block 10 block2 block4 block1 block5 0x1245 Heap des Programms 0x7890 Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 31 / 62

malloc Gibt Zeiger vom Typ void * zurück Typ der Daten, die im Speicherblock hinterlegt werden sollen ist malloc nicht bekannt Typ muss mittels Cast umgewandelt werden int *ptr = NULL;... ptr = (int *)malloc(size); Es darf nicht ausserhalb des allokierten Speicherblocks zugegriffen werden Speicher könnte anderen Prozessen oder anderen Datenstrukturen des gleichen Prozesses gehören Buffer Overflow Fehler nicht erkannt oder Segmentation Violation (SIGSEGV) Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 32 / 62

malloc Gibt Zeiger vom Typ void * zurück Typ der Daten, die im Speicherblock hinterlegt werden sollen ist malloc nicht bekannt Typ muss mittels Cast umgewandelt werden int *ptr = NULL;... ptr = (int *)malloc(size); Es darf nicht ausserhalb des allokierten Speicherblocks zugegriffen werden Speicher könnte anderen Prozessen oder anderen Datenstrukturen des gleichen Prozesses gehören Buffer Overflow Fehler nicht erkannt oder Segmentation Violation (SIGSEGV) Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 32 / 62

Malloc (2) Ähnliche Systemfunktionen: void *calloc(size_t nmemb, size_t size); Liefert Feld (Array) mit nmemb Elementen, wobei jedes Element size Bytes groß ist Vergleichbar mit malloc(nmemb * size) Speicherblock mit 0x00 initialisiert Andere Programmiersprachen verwenden ähnliche Operatoren Typisierung oft gleich mitgelieft Cast ist nicht mehr nötig C++: MyClass *object = new MyClass(); Java: MyClass object = new MyClass(); Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 33 / 62

Malloc (2) Ähnliche Systemfunktionen: void *calloc(size_t nmemb, size_t size); Liefert Feld (Array) mit nmemb Elementen, wobei jedes Element size Bytes groß ist Vergleichbar mit malloc(nmemb * size) Speicherblock mit 0x00 initialisiert Andere Programmiersprachen verwenden ähnliche Operatoren Typisierung oft gleich mitgelieft Cast ist nicht mehr nötig C++: MyClass *object = new MyClass(); Java: MyClass object = new MyClass(); Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 33 / 62

free Angeforderte Speicherblöcke müssen wieder freigegeben werden free(ptr); Sobald nicht mehr gebraucht Nur Zeiger verwenden, die malloc zurückgibt Nur dynamisch allokierter Speicher Zeiger auf Speicherblock darf bis zum free nicht verloren gehen! Teile von Blöcken können nicht freigegeben werden Freigabe geschieht automatisch bei Programmende Nicht darauf verlassen! Viele Programme beenden sich nie Ein Block kann nur genau 1x freigegeben werden Mehrfache free Operationen könnten einen falschen Block freigeben oder zum Programmabsturz führen Block darf nach Freigabe nicht mehr verwendet werden Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 34 / 62

free Angeforderte Speicherblöcke müssen wieder freigegeben werden free(ptr); Sobald nicht mehr gebraucht Nur Zeiger verwenden, die malloc zurückgibt Nur dynamisch allokierter Speicher Zeiger auf Speicherblock darf bis zum free nicht verloren gehen! Teile von Blöcken können nicht freigegeben werden Freigabe geschieht automatisch bei Programmende Nicht darauf verlassen! Viele Programme beenden sich nie Ein Block kann nur genau 1x freigegeben werden Mehrfache free Operationen könnten einen falschen Block freigeben oder zum Programmabsturz führen Block darf nach Freigabe nicht mehr verwendet werden Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 34 / 62

free Angeforderte Speicherblöcke müssen wieder freigegeben werden free(ptr); Sobald nicht mehr gebraucht Nur Zeiger verwenden, die malloc zurückgibt Nur dynamisch allokierter Speicher Zeiger auf Speicherblock darf bis zum free nicht verloren gehen! Teile von Blöcken können nicht freigegeben werden Freigabe geschieht automatisch bei Programmende Nicht darauf verlassen! Viele Programme beenden sich nie Ein Block kann nur genau 1x freigegeben werden Mehrfache free Operationen könnten einen falschen Block freigeben oder zum Programmabsturz führen Block darf nach Freigabe nicht mehr verwendet werden Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 34 / 62

free Angeforderte Speicherblöcke müssen wieder freigegeben werden free(ptr); Sobald nicht mehr gebraucht Nur Zeiger verwenden, die malloc zurückgibt Nur dynamisch allokierter Speicher Zeiger auf Speicherblock darf bis zum free nicht verloren gehen! Teile von Blöcken können nicht freigegeben werden Freigabe geschieht automatisch bei Programmende Nicht darauf verlassen! Viele Programme beenden sich nie Ein Block kann nur genau 1x freigegeben werden Mehrfache free Operationen könnten einen falschen Block freigeben oder zum Programmabsturz führen Block darf nach Freigabe nicht mehr verwendet werden Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 34 / 62

Free (2) Freigegebener Block (oder ein Teil davon) kann beim nächsten malloc wieder vergeben werden Speicherverwaltung im Betriebssystem Andere Programmiersprachen verwenden intern auch free: C++: delete-operator und/oder Garbage Collection Java: Garbage Collection Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 35 / 62

Free (2) Freigegebener Block (oder ein Teil davon) kann beim nächsten malloc wieder vergeben werden Speicherverwaltung im Betriebssystem Andere Programmiersprachen verwenden intern auch free: C++: delete-operator und/oder Garbage Collection Java: Garbage Collection Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 35 / 62

realloc Vergrößern von Speicherblöcken ist nicht direkt möglich Andere Speicherblöcke können physisch im Speicher dahinter liegen Neuer Speicherblock muss allokiert und Daten umkopiert werden int *ptr = NULL; int *newptr = NULL; ptr = (int *)malloc(init_size);... newptr = (int *)realloc(ptr, new_size); Einfach Verlängerung des allokierten Blocks, wenn möglich Alter Speicherblock wird automatisch freigegeben Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 36 / 62

sizeof Anzahl der Bytes von Datentypen kann von Plattform zu Plattform variieren Z. B. unterschiedliche Größen von int Werten (32 vs. 64 Bit auf 32/64 Bit Prozessoren) Ermitteln der jeweiligen Größe sizeof variable sizeof(datatype) Garantien des C Standards: ( sizeof(char) == 1 ) ( sizeof(char) <= sizeof(smallint) <= sizeof(int) <= sizeof(long) <= sizeof(long long) ) Wenn möglich, auf <stdint.h> zurückgreifen Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 37 / 62

sizeof Anzahl der Bytes von Datentypen kann von Plattform zu Plattform variieren Z. B. unterschiedliche Größen von int Werten (32 vs. 64 Bit auf 32/64 Bit Prozessoren) Ermitteln der jeweiligen Größe sizeof variable sizeof(datatype) Garantien des C Standards: ( sizeof(char) == 1 ) ( sizeof(char) <= sizeof(smallint) <= sizeof(int) <= sizeof(long) <= sizeof(long long) ) Wenn möglich, auf <stdint.h> zurückgreifen Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 37 / 62

Sizeof Operator Arrays Arrays sind nicht identisch zu Zeigern für sizeof int a[5] = 0 ; sizeof a == 20; sizeof &a[0] == 4; sizeof gibt Anzahl der Bytes des gesamten Arrays Compiler muss zur Compilezeit Größe des Arrays kennen Array darf nicht als Zeiger interpretiert werden Größe eines einzelnen Elements nicht immer bekannt sizeof array / sizeof array[0] Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 38 / 62

Sizeof Operator Padding/Alignment Unterschiedliche Optimierungsstrategien der Compiler Unterschiedliche Mächtigkeit/Performance der Adressierungsbefehle des Prozessors Zugriff auf Speicheradressen, die ein Vielfaches von 4 Bytes sind, oft schneller als Adressierung einzelner Bytes Padding-Bytes können vom Compiler eingeschoben werden Genaue Größe von Strukturen oft nicht bekannt struct s { char c; int i; }; Ergebnis von sizeof(struct s) auf 32 bit System:??? Programme sollten sich nie auf bestimmte Größe verlassen sizeof verwenden, oder gezielt byte-weise operieren Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 39 / 62

Sizeof Operator Padding/Alignment Unterschiedliche Optimierungsstrategien der Compiler Unterschiedliche Mächtigkeit/Performance der Adressierungsbefehle des Prozessors Zugriff auf Speicheradressen, die ein Vielfaches von 4 Bytes sind, oft schneller als Adressierung einzelner Bytes Padding-Bytes können vom Compiler eingeschoben werden Genaue Größe von Strukturen oft nicht bekannt struct s { char c; int i; }; Ergebnis von sizeof(struct s) auf 32 bit System:??? Programme sollten sich nie auf bestimmte Größe verlassen sizeof verwenden, oder gezielt byte-weise operieren Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 39 / 62

Sizeof Operator Padding/Alignment Unterschiedliche Optimierungsstrategien der Compiler Unterschiedliche Mächtigkeit/Performance der Adressierungsbefehle des Prozessors Zugriff auf Speicheradressen, die ein Vielfaches von 4 Bytes sind, oft schneller als Adressierung einzelner Bytes Padding-Bytes können vom Compiler eingeschoben werden Genaue Größe von Strukturen oft nicht bekannt struct s { char c; int i; }; Ergebnis von sizeof(struct s) auf 32 bit System:??? Programme sollten sich nie auf bestimmte Größe verlassen sizeof verwenden, oder gezielt byte-weise operieren Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 39 / 62

Sizeof Operator Padding/Alignment Unterschiedliche Optimierungsstrategien der Compiler Unterschiedliche Mächtigkeit/Performance der Adressierungsbefehle des Prozessors Zugriff auf Speicheradressen, die ein Vielfaches von 4 Bytes sind, oft schneller als Adressierung einzelner Bytes Padding-Bytes können vom Compiler eingeschoben werden Genaue Größe von Strukturen oft nicht bekannt struct s { char c; int i; }; Ergebnis von sizeof(struct s) auf 32 bit System: 8 Bytes Programme sollten sich nie auf bestimmte Größe verlassen sizeof verwenden, oder gezielt byte-weise operieren Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 39 / 62

Sizeof Operator Padding/Alignment Unterschiedliche Optimierungsstrategien der Compiler Unterschiedliche Mächtigkeit/Performance der Adressierungsbefehle des Prozessors Zugriff auf Speicheradressen, die ein Vielfaches von 4 Bytes sind, oft schneller als Adressierung einzelner Bytes Padding-Bytes können vom Compiler eingeschoben werden Genaue Größe von Strukturen oft nicht bekannt struct s { char c; int i; }; Ergebnis von sizeof(struct s) auf 32 bit System: 8 Bytes Programme sollten sich nie auf bestimmte Größe verlassen sizeof verwenden, oder gezielt byte-weise operieren Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 39 / 62

Sizeof Operator Verwendung sizeof berechnet Größe eines Wertes oder eines Datentyps size = sizeof(int); size = sizeof(struct mystruct); size = sizeof myvalue; Klammern bei Datentypen notwendig Variablen brauchen nicht geklammert zu werden und sollten es auch nicht Compiler kann besser Fehler erkennen und melden Anzahl an Bytes, die die physisch Repräsentation im Speicher benötigt ptr = (int *)malloc(n * sizeof(int)); Kann bereits zur Übersetzungszeit errechnet werden und belastet somit nicht die Laufzeit Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 40 / 62

Sizeof Operator Verwendung sizeof berechnet Größe eines Wertes oder eines Datentyps size = sizeof(int); size = sizeof(struct mystruct); size = sizeof myvalue; Klammern bei Datentypen notwendig Variablen brauchen nicht geklammert zu werden und sollten es auch nicht Compiler kann besser Fehler erkennen und melden Anzahl an Bytes, die die physisch Repräsentation im Speicher benötigt ptr = (int *)malloc(n * sizeof(int)); Kann bereits zur Übersetzungszeit errechnet werden und belastet somit nicht die Laufzeit Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 40 / 62

Sizeof Operator Verwendung sizeof berechnet Größe eines Wertes oder eines Datentyps size = sizeof(int); size = sizeof(struct mystruct); size = sizeof myvalue; Klammern bei Datentypen notwendig Variablen brauchen nicht geklammert zu werden und sollten es auch nicht Compiler kann besser Fehler erkennen und melden Anzahl an Bytes, die die physisch Repräsentation im Speicher benötigt ptr = (int *)malloc(n * sizeof(int)); Kann bereits zur Übersetzungszeit errechnet werden und belastet somit nicht die Laufzeit Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 40 / 62

memset, memcopy, und memmove memset Angeforderte Speicherblöcke (malloc) immer initialisieren! memset(ptr, 0x00, size); Bei sicherheitskritischen Anwendung Leeren vor dem Freigeben memcopy Kopieren zwischen überlappungsfreien Speicherblöcken memcpy(destination, source, size); memmove Kopieren zwischen überlappenden oder überlappungsfreien Speicherblöcken memmove(destination, source, size); Nicht so effizient wie memcopy Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 41 / 62

memset, memcopy, und memmove memset Angeforderte Speicherblöcke (malloc) immer initialisieren! memset(ptr, 0x00, size); Bei sicherheitskritischen Anwendung Leeren vor dem Freigeben memcopy Kopieren zwischen überlappungsfreien Speicherblöcken memcpy(destination, source, size); memmove Kopieren zwischen überlappenden oder überlappungsfreien Speicherblöcken memmove(destination, source, size); Nicht so effizient wie memcopy Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 41 / 62

memset, memcopy, und memmove memset Angeforderte Speicherblöcke (malloc) immer initialisieren! memset(ptr, 0x00, size); Bei sicherheitskritischen Anwendung Leeren vor dem Freigeben memcopy Kopieren zwischen überlappungsfreien Speicherblöcken memcpy(destination, source, size); memmove Kopieren zwischen überlappenden oder überlappungsfreien Speicherblöcken memmove(destination, source, size); Nicht so effizient wie memcopy Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 41 / 62

Ulimit (UNIX / Linux) Legt Maximum von Resourcen für einen Nutzer/Prozess fest: Maximal nutzbarer Speicherbereich (virtuell) Größe des Stacks Größe von core Dateien Größe des data segment eines Prozesses Größe von Dateien, die ein Prozess anlegen kann Anzahl der geöffneten Dateien Größe des ge pin ten Speicherbereichs Blockgröße bei Pipes Anzahl der Prozesse eines Nutzers CPU-Zeit Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 42 / 62

Tipps Speicherallokation kann fehlschlagen!! Ergebnis ist dann NULL-Zeiger Ergebnis muss immer überprüft werden Speicherblock nach free nicht weiter verwenden Am besten Zeiger auf NULL setzen: free(ptr); ptr = NULL; Kann mit Macros automatisch gemacht werden Alle Variablen sofort bei Deklaration initialisieren char *str = NULL;... str = (char *)malloc(strlen(orig_str)+1); if (!str) {... } memset(str, 0x00, strlen(orig_str)+1); Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 43 / 62

Tipps Speicherallokation kann fehlschlagen!! Ergebnis ist dann NULL-Zeiger Ergebnis muss immer überprüft werden Speicherblock nach free nicht weiter verwenden Am besten Zeiger auf NULL setzen: free(ptr); ptr = NULL; Kann mit Macros automatisch gemacht werden Alle Variablen sofort bei Deklaration initialisieren char *str = NULL;... str = (char *)malloc(strlen(orig_str)+1); if (!str) {... } memset(str, 0x00, strlen(orig_str)+1); Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 43 / 62

Tipps Speicherallokation kann fehlschlagen!! Ergebnis ist dann NULL-Zeiger Ergebnis muss immer überprüft werden Speicherblock nach free nicht weiter verwenden Am besten Zeiger auf NULL setzen: free(ptr); ptr = NULL; Kann mit Macros automatisch gemacht werden Alle Variablen sofort bei Deklaration initialisieren char *str = NULL;... str = (char *)malloc(strlen(orig_str)+1); if (!str) {... } memset(str, 0x00, strlen(orig_str)+1); Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 43 / 62

Potentielle Probleme (1) Keine gute Kontrolle über Speicher Keine Gruppierung von Speicher (Pooling) Keine Fehlermeldung beim falschen Freigeben Programm stürzt eventuell ab Vielleicht auch unerwarteter Stelle Nur unzureichende Memory-Debugging Facilities Spezielle Bibliotheken oder eigene Implementierung nötig Buffer Overflow Zugriff ausserhalb des aktuellen Speicherblocks verhindern In Programmen oft keine/unzureichende Prüfung von Überläufen Kann sich zu Sicherheitsproblemen ausweiten Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 44 / 62

Potentielle Probleme (1) Keine gute Kontrolle über Speicher Keine Gruppierung von Speicher (Pooling) Keine Fehlermeldung beim falschen Freigeben Programm stürzt eventuell ab Vielleicht auch unerwarteter Stelle Nur unzureichende Memory-Debugging Facilities Spezielle Bibliotheken oder eigene Implementierung nötig Buffer Overflow Zugriff ausserhalb des aktuellen Speicherblocks verhindern In Programmen oft keine/unzureichende Prüfung von Überläufen Kann sich zu Sicherheitsproblemen ausweiten Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 44 / 62

Potentielle Probleme (1) Keine gute Kontrolle über Speicher Keine Gruppierung von Speicher (Pooling) Keine Fehlermeldung beim falschen Freigeben Programm stürzt eventuell ab Vielleicht auch unerwarteter Stelle Nur unzureichende Memory-Debugging Facilities Spezielle Bibliotheken oder eigene Implementierung nötig Buffer Overflow Zugriff ausserhalb des aktuellen Speicherblocks verhindern In Programmen oft keine/unzureichende Prüfung von Überläufen Kann sich zu Sicherheitsproblemen ausweiten Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 44 / 62

Potentielle Probleme (2) Memory Leaks angeforderter Speicher wird nie freigegeben Zeiger auf Speicherblock ist verloren gegangen Unbedarftheit des Programmierers Funktionen dürfen keinen Zeiger in den Stack zurückgeben Informationen auf dem Stack sind beim Verlassen der Funktion nicht mehr gültig free auf Objekt auf dem Stack nicht zulässig Führt meist zum Absturz des Programms Irgendwann, irgendwo Speicheroperationen kosten Zeit Wenn möglich, mehrere Informationen in einen gemeinsamen Speicherblock legen Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 45 / 62

Potentielle Probleme (2) Memory Leaks angeforderter Speicher wird nie freigegeben Zeiger auf Speicherblock ist verloren gegangen Unbedarftheit des Programmierers Funktionen dürfen keinen Zeiger in den Stack zurückgeben Informationen auf dem Stack sind beim Verlassen der Funktion nicht mehr gültig free auf Objekt auf dem Stack nicht zulässig Führt meist zum Absturz des Programms Irgendwann, irgendwo Speicheroperationen kosten Zeit Wenn möglich, mehrere Informationen in einen gemeinsamen Speicherblock legen Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 45 / 62

Potentielle Probleme (2) Memory Leaks angeforderter Speicher wird nie freigegeben Zeiger auf Speicherblock ist verloren gegangen Unbedarftheit des Programmierers Funktionen dürfen keinen Zeiger in den Stack zurückgeben Informationen auf dem Stack sind beim Verlassen der Funktion nicht mehr gültig free auf Objekt auf dem Stack nicht zulässig Führt meist zum Absturz des Programms Irgendwann, irgendwo Speicheroperationen kosten Zeit Wenn möglich, mehrere Informationen in einen gemeinsamen Speicherblock legen Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 45 / 62

Potentielle Probleme (2) Memory Leaks angeforderter Speicher wird nie freigegeben Zeiger auf Speicherblock ist verloren gegangen Unbedarftheit des Programmierers Funktionen dürfen keinen Zeiger in den Stack zurückgeben Informationen auf dem Stack sind beim Verlassen der Funktion nicht mehr gültig free auf Objekt auf dem Stack nicht zulässig Führt meist zum Absturz des Programms Irgendwann, irgendwo Speicheroperationen kosten Zeit Wenn möglich, mehrere Informationen in einen gemeinsamen Speicherblock legen Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 45 / 62

Outline 1 Einführung 2 Compiler Compile-Prozess Compiler 3 Zeiger & Arrays Grundlagen Arrays 4 Speicherverwaltung Arten von Speicher Funktionen Tipps & Hinweise 5 Präprozessor & Macros 6 Aufgaben Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 46 / 62

Einsatz von Macros Plattformspezifische Definitionen? Wie Header-Dateien einbinden? Ursprünglich keine Inline-Funktionen Work-around? Macros und Präprozessor-Direktiven Einfache Textersetzung Parameterisiert vs. nicht-parameterisiert C Präprozessor ersetzt Vorkommen der Macros mit entsprechenden Text Single sweep Nicht zur Definition von Datentypen verwenden typedef wesentlich geeigneter! Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 47 / 62

Einsatz von Macros Plattformspezifische Definitionen? Wie Header-Dateien einbinden? Ursprünglich keine Inline-Funktionen Work-around? Macros und Präprozessor-Direktiven Einfache Textersetzung Parameterisiert vs. nicht-parameterisiert C Präprozessor ersetzt Vorkommen der Macros mit entsprechenden Text Single sweep Nicht zur Definition von Datentypen verwenden typedef wesentlich geeigneter! Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 47 / 62

Einsatz von Macros Plattformspezifische Definitionen? Wie Header-Dateien einbinden? Ursprünglich keine Inline-Funktionen Work-around? Macros und Präprozessor-Direktiven Einfache Textersetzung Parameterisiert vs. nicht-parameterisiert C Präprozessor ersetzt Vorkommen der Macros mit entsprechenden Text Single sweep Nicht zur Definition von Datentypen verwenden typedef wesentlich geeigneter! Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 47 / 62

Einsatz von Macros Plattformspezifische Definitionen? Wie Header-Dateien einbinden? Ursprünglich keine Inline-Funktionen Work-around? Macros und Präprozessor-Direktiven Einfache Textersetzung Parameterisiert vs. nicht-parameterisiert C Präprozessor ersetzt Vorkommen der Macros mit entsprechenden Text Single sweep Nicht zur Definition von Datentypen verwenden typedef wesentlich geeigneter! Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 47 / 62

Definition von Macros #define macro ersetzung #define macro(parameterliste) ersetzung Wörtliche Ersetzung von <macro> mit <ersetzung> Parameterliste wird gegen Argumente beim Aufruf des Macros ausgetauscht Ersetzung kann leer sein Entfernt Macro aus dem Quelltext Kann gut für Tracing/Debugging eingesetzt werden Löschen von Macros #undef macro Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 48 / 62

Definition von Macros Beispiel #define MAX(a, b) ((a) > (b)? (a) : (b))... res = MAX(in1, in2); res = ((in1) > (in2)? (in1) : (in2)); Macros können geschachtelt werden Macro A kann Macro B in der Ersetzung verwenden Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 49 / 62

Definition von Macros Beispiel #define MAX(a, b) ((a) > (b)? (a) : (b))... res = MAX(in1, in2); res = ((in1) > (in2)? (in1) : (in2)); Macros können geschachtelt werden Macro A kann Macro B in der Ersetzung verwenden Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 49 / 62

Definition von Macros Beispiel #define MAX(a, b) ((a) > (b)? (a) : (b))... res = MAX(in1, in2); res = ((in1) > (in2)? (in1) : (in2)); Macros können geschachtelt werden Macro A kann Macro B in der Ersetzung verwenden Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 49 / 62

Präprozessor-Direktiven 1 Einbinden von Header-Dateien #include "datei" #include <datei> Transitives Einbinden möglich 2 Header-Datei kann mehrfach eingebunden werden Meist nicht erwünscht Doppelte Deklarationen 3 Macros zum Unterbinden mehrfachen Einbindens #if!defined( DATEI_H ) #define DATEI_H... #endif /* DATEI_H */ Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 50 / 62

Präprozessor-Direktiven 1 Einbinden von Header-Dateien #include "datei" #include <datei> Transitives Einbinden möglich 2 Header-Datei kann mehrfach eingebunden werden Meist nicht erwünscht Doppelte Deklarationen 3 Macros zum Unterbinden mehrfachen Einbindens #if!defined( DATEI_H ) #define DATEI_H... #endif /* DATEI_H */ Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 50 / 62

Präprozessor-Direktiven 1 Einbinden von Header-Dateien #include "datei" #include <datei> Transitives Einbinden möglich 2 Header-Datei kann mehrfach eingebunden werden Meist nicht erwünscht Doppelte Deklarationen 3 Macros zum Unterbinden mehrfachen Einbindens #if!defined( DATEI_H ) #define DATEI_H... #endif /* DATEI_H */ Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 50 / 62

Kontrollfluss 4 Bedingungen #if...... #elif... #else... #endif Nur mit Konstanten oder Macros kein C Code! Können logische Verknüpfungen ( und &&) verwenden 5 Macros in Bedingungen Test ob Macro definiert? #if defined(macro) Alternativ: #ifdef MACRO Kann aber nur einzelnes Macro testen Auswertung des Macro-Wertes #if MACRO Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 51 / 62

Kontrollfluss 4 Bedingungen #if...... #elif... #else... #endif Nur mit Konstanten oder Macros kein C Code! Können logische Verknüpfungen ( und &&) verwenden 5 Macros in Bedingungen Test ob Macro definiert? #if defined(macro) Alternativ: #ifdef MACRO Kann aber nur einzelnes Macro testen Auswertung des Macro-Wertes #if MACRO Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 51 / 62

Warnungen und Fehler 6 Warnungen und Fehler #warning "meldung" #error "meldung" Warnung wird ausgegeben, Präcompile-Vorgang wird fortgesetzt Ausser bei Option -Werror (bei gcc) Fehlermeldung wird ausgegeben, Präcompile-Vorgang wird abgebrochen Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 52 / 62

Spezielle Macros FILE Name der Übersetzungseinheit Nicht die Datei, in der das Macro genutzt wurde. LINE Zeile in der Übersetzungseinheit, in der das Macro auftaucht Nicht die Datei, in der das Macro genutzt wurde. Auch bei geschachtelten Macros Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 53 / 62

Quoting von Macro-Argumenten Macros werden nicht innerhalb von Strings expandiert Macro-Argumente können in Strings umgewandelt werden #define QUOTE(x) #x printf("%s\n", QUOTE(1+2)); printf("%s\n", "1+2"); Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 54 / 62

Quoting von Macro-Argumenten Macros werden nicht innerhalb von Strings expandiert Macro-Argumente können in Strings umgewandelt werden #define QUOTE(x) #x printf("%s\n", QUOTE(1+2)); printf("%s\n", "1+2"); Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 54 / 62

Probleme von Macros #define MAX(a, b) ((a) > (b)? (a) : (b)) Reine Textersetzung Keine Typverifikation für a und b signed vs. unsigned Typen überhaupt vergleichbar? Klammerung nötig c = MAX(d1 > 0? d1 : d2, b); c = d1 > 0? d1 : d2 > b? d1 > 0? d1 : d2 : b; Seiteneffekte c = MAX(a++, b); c = ((a++) > (b)? (a++) : (b)) Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 55 / 62

Probleme von Macros #define MAX(a, b) ((a) > (b)? (a) : (b)) Reine Textersetzung Keine Typverifikation für a und b signed vs. unsigned Typen überhaupt vergleichbar? Klammerung nötig c = MAX(d1 > 0? d1 : d2, b); c = d1 > 0? d1 : d2 > b? d1 > 0? d1 : d2 : b; Seiteneffekte c = MAX(a++, b); c = ((a++) > (b)? (a++) : (b)) Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 55 / 62

Probleme von Macros #define MAX(a, b) ((a) > (b)? (a) : (b)) Reine Textersetzung Keine Typverifikation für a und b signed vs. unsigned Typen überhaupt vergleichbar? Klammerung nötig c = MAX(d1 > 0? d1 : d2, b); c = d1 > 0? d1 : d2 > b? d1 > 0? d1 : d2 : b; Seiteneffekte c = MAX(a++, b); c = ((a++) > (b)? (a++) : (b)) Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 55 / 62

Outline 1 Einführung 2 Compiler Compile-Prozess Compiler 3 Zeiger & Arrays Grundlagen Arrays 4 Speicherverwaltung Arten von Speicher Funktionen Tipps & Hinweise 5 Präprozessor & Macros 6 Aufgaben Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 56 / 62

Allgemeines Aktivieren der Compiler-Warnungen Bei selbstgeschriebenen Programmen sind alle Warnungen zu bearbeiten/zu beseitigen Unterdrücken der Warnungen nicht zulässig Ausgaben sind mittels printf auf die Standardausgabe zu leiten Beispiel in simple.c (siehe Aufgabe 1) zu finden Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 57 / 62

Aufgabe 1 Übersetzen Sie das vorgegebene Programm simple.c auf Ihrem Rechner. Erzeugen Sie dabei Dateien, die (a) Preprozessor-Ausgabe, (b) Assembler-Code, (c) Objekt-Datei, und (d) Ausführbares Programm (erzeugt von der Objektdatei). Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 58 / 62

Aufgabe 2 Schreiben Sie ein einzelnes Programm, welches folgende Speicherblöcke anlegt. Strukturieren Sie hierbei das Programm so, dass jede Speicheranforderung in einer eigenen Routine abgewickelt wird. (a) Dynamische Allokation von 123 Integer-Werten, (b) Allokation eines String für 67 Textzeichen auf dem Stack, (c) Eine globale Variable vom Typ struct s { int i; char c; };, (d) Legen Sie ein Array für 10 Strings (jeweils mit beliebiger Länge) an. Schreiben Sie jeweils mindestens einen (passenden) Wert in den jeweiligen Speicherbereich. Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 59 / 62

Aufgabe 3 Definieren Sie ein Macro, das den absoluten Wert einer Integer-Zahl ermittelt. Verwenden Sie dieses Macro in einem selbstgeschriebenen Programm, das eine (beliebige) Zahl akzeptiert, den absoluten Wert bildet und das Ergebnis auf der Standardausgabe ausgibt. Die vorgegebete Zahl ist mittels eines Macros als Compiler-Option beim Übersetzen des Programms zu übergeben. Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 60 / 62

Aufgabe 4 Definieren Sie die folgenden drei Macros: (a) Zum Ermitteln der Länge eines Strings (ohne die Funktion strlen zu verwenden); d. h. implementieren Sie die Funktionalität selbst, (b) Zum Freigeben von zuvor angeforderten Speicher und gleichzeitig den übergebenen Zeiger auf NULL zu setzen, (c) Zum Umwandeln einer Variable in ihren String mit dem Variablennamen. Das erste der Macros soll nur auf der Linux-Plattform wie beschrieben gültig sein (Macro LINUX ist definiert). Auf AIX ist das erste Macro auf strlen abzubilden, und auf allen anderen Plattformen ist ein Fehler von Präprozessor auszugeben. Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 61 / 62

Aufgabe 5 Nutzen Sie die Macros aus Aufgabe 4 in einem selbstgeschriebenen Programm, das: (a) einen beliebigen, vorgegebenen String in einen dynamisch allokierten Puffer kopiert, (b) den Inhalt dieses Puffers ausgibt, (c) zu Debugging-Zwecken eine beliebige Variable (mit dessen Namen und Integer-Wert) auf der Standard-Ausgabe ausgibt, (d) den Puffer freigibt, und (e) den Zeiger-Wert auf die Standardausgabe ausgibt. Testen Sie das Programm. Erzeugen Sie zusätzlich die Präprozessor-Ausgabe. Knut Stolze (DBIS) C/C++ Programmierung 2006 10 18 62 / 62