diff --git a/20210128/aufgabe-1.c b/20210128/aufgabe-1.c new file mode 100644 index 0000000000000000000000000000000000000000..cb09b0e10aade5c202ed88fddcb2e52d700d9915 --- /dev/null +++ b/20210128/aufgabe-1.c @@ -0,0 +1,16 @@ +#include <stdio.h> +#include <stdint.h> + +typedef struct +{ + uint32_t a; + uint64_t b; + uint8_t c; +} three_numbers; + +int main (void) +{ + three_numbers xyz = { 1819042120, 2410670883059281007, 0 }; + printf ("%s\n", &xyz); + return 0; +} diff --git a/20210128/aufgabe-2.c b/20210128/aufgabe-2.c new file mode 100644 index 0000000000000000000000000000000000000000..47595ef0658e94d76a42263e82200f94895cdeea --- /dev/null +++ b/20210128/aufgabe-2.c @@ -0,0 +1,23 @@ +#include <stdio.h> +#include <string.h> + +typedef struct +{ + char first_name[10]; + char family_name[20]; + char day, month; + int year; +} person; + +int main (void) +{ + person sls; + sls.day = 26; + sls.month = 7; + sls.year = 1951; + strcpy (sls.first_name, "Sabine"); + strcpy (sls.family_name, "Leutheusser-Schnarrenberger"); + printf ("%s %s wurde am %d.%d.%d geboren.\n", + sls.first_name, sls.family_name, sls.day, sls.month, sls.year); + return 0; +} diff --git a/20210128/aufgabe-3a.c b/20210128/aufgabe-3a.c new file mode 100644 index 0000000000000000000000000000000000000000..61b6e79400afbb8ac0609eb1b72c04b83a0fce41 --- /dev/null +++ b/20210128/aufgabe-3a.c @@ -0,0 +1,50 @@ +#include <stdio.h> + +#define ANIMAL 0 +#define WITH_WINGS 1 +#define WITH_LEGS 2 + +typedef struct animal +{ + int type; + char *name; +} animal; + +typedef struct with_wings +{ + int wings; +} with_wings; + +typedef struct with_legs +{ + int legs; +} with_legs; + +int main (void) +{ + animal *a[2]; + + animal duck; + a[0] = &duck; + a[0]->type = WITH_WINGS; + a[0]->name = "duck"; + a[0]->wings = 2; + + animal cow; + a[1] = &cow; + a[1]->type = WITH_LEGS; + a[1]->name = "cow"; + a[1]->legs = 4; + + for (int i = 0; i < 2; i++) + if (a[i]->type == WITH_LEGS) + printf ("A %s has %d legs.\n", a[i]->name, + ((with_legs *) a[i])-> legs); + else if (a[i]->type == WITH_WINGS) + printf ("A %s has %d wings.\n", a[i]->name, + ((with_wings *) a[i])-> wings); + else + printf ("Error in animal: %s\n", a[i]->name); + + return 0; +} diff --git a/20210128/aufgabe-3b.c b/20210128/aufgabe-3b.c new file mode 100644 index 0000000000000000000000000000000000000000..2cf3b56f4540f399d3761b0de929d80a1f1de611 --- /dev/null +++ b/20210128/aufgabe-3b.c @@ -0,0 +1,50 @@ +#include <stdio.h> + +#define ANIMAL 0 +#define WITH_WINGS 1 +#define WITH_LEGS 2 + +typedef struct animal +{ + int type; + char *name; +} animal; + +typedef struct with_wings +{ + int wings; +} with_wings; + +typedef struct with_legs +{ + int legs; +} with_legs; + +int main (void) +{ + animal *a[2]; + + animal duck; + a[0] = &duck; + a[0]->type = WITH_WINGS; + a[0]->name = "duck"; + ((with_wings *) a[0])->wings = 2; + + animal cow; + a[1] = &cow; + a[1]->type = WITH_LEGS; + a[1]->name = "cow"; + ((with_legs *) a[1])->legs = 4; + + for (int i = 0; i < 2; i++) + if (a[i]->type == WITH_LEGS) + printf ("A %s has %d legs.\n", a[i]->name, + ((with_legs *) a[i])-> legs); + else if (a[i]->type == WITH_WINGS) + printf ("A %s has %d wings.\n", a[i]->name, + ((with_wings *) a[i])-> wings); + else + printf ("Error in animal: %s\n", a[i]->name); + + return 0; +} diff --git a/20210128/hello-gtk.png b/20210128/hello-gtk.png new file mode 120000 index 0000000000000000000000000000000000000000..cca99209d86683a9a3b0f70bbc149780bae10ba6 --- /dev/null +++ b/20210128/hello-gtk.png @@ -0,0 +1 @@ +../common/hello-gtk.png \ No newline at end of file diff --git a/20210128/hp-20210128.pdf b/20210128/hp-20210128.pdf new file mode 100644 index 0000000000000000000000000000000000000000..06019da71ff58c18d777f5090b46f6a469ebf29e Binary files /dev/null and b/20210128/hp-20210128.pdf differ diff --git a/20210128/hp-20210128.tex b/20210128/hp-20210128.tex new file mode 100644 index 0000000000000000000000000000000000000000..b5e2211a60e816e0459c7e1d5130e716f0e66cc3 --- /dev/null +++ b/20210128/hp-20210128.tex @@ -0,0 +1,1404 @@ +% hp-20210128.pdf - Lecture Slides on Low-Level Programming +% Copyright (C) 2012, 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Peter Gerwinski +% +% This document is free software: you can redistribute it and/or +% modify it either under the terms of the Creative Commons +% Attribution-ShareAlike 3.0 License, or under the terms of the +% GNU General Public License as published by the Free Software +% Foundation, either version 3 of the License, or (at your option) +% any later version. +% +% This document is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this document. If not, see <http://www.gnu.org/licenses/>. +% +% You should have received a copy of the Creative Commons +% Attribution-ShareAlike 3.0 Unported License along with this +% document. If not, see <http://creativecommons.org/licenses/>. + +% README: Objektorientierte Programmierung + +\documentclass[10pt,t]{beamer} + +\usepackage{pgslides} +\usepackage{rotating} +\usepackage{tikz} + +\title{Hardwarenahe Programmierung} +\author{Prof.\ Dr.\ rer.\ nat.\ Peter Gerwinski} +\date{28.\ Januar 2021} + +\begin{document} + +\maketitleframe + +\nosectionnonumber{\inserttitle} + +\begin{frame} + + \shownosectionnonumber + + \begin{itemize} + \item[\textbf{1}] \textbf{Einführung} + \hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp}}} + \item[\textbf{2}] \textbf{Einführung in C} + \item[\textbf{3}] \textbf{Bibliotheken} + \item[\textbf{4}] \textbf{Algorithmen} + \item[\textbf{5}] \textbf{Hardwarenahe Programmierung} + \begin{itemize} + \item[5.1] Bit-Operationen + \item[5.2] I/O-Ports + \color{medgreen} + \item[5.3] Interrupts + \item[5.4] volatile-Variable + \item[5.6] Byte-Reihenfolge -- Endianness + \item[5.7] Binärdarstellung negativer Zahlen + \item[5.8] Speicherausrichtung -- Alignment + \end{itemize} + \item[\textbf{6}] \textbf{Objektorientierte Programmierung} + \begin{itemize} + \color{red} + \item[6.0] Dynamische Speicherverwaltung + \item[6.1] Konzepte und Ziele + \vspace*{-\smallskipamount} + \item[\dots] +% \item[6.2] Beispiel: Zahlen und Buchstaben +% \color{red} +% \item[6.3] Unions +% \item[6.4] Virtuelle Methoden +% \color{black} +% \item[6.5] Beispiel: Graphische Benutzeroberfläche (GUI) +% \item[6.6] Ausblick: C++ + \end{itemize} + \item[\textbf{7}] \textbf{Datenstrukturen} + \vspace*{-1cm} + \end{itemize} + +\end{frame} + +\setcounter{section}{4} +\section{Hardwarenahe Programmierung} +\subsection{Bit-Operationen} +\subsubsection{Zahlensysteme} + +\begin{frame}[fragile] + + \showsubsubsection + + \begin{tabular}{rlrlrc} + \qquad 000 & \bf 0 \hspace*{1.5cm} & 0000 & \bf 0 & \quad 1000 & \bf 8\\ + 001 & \bf 1 & 0001 & \bf 1 & 1001 & \bf 9\\ + 010 & \bf 2 & 0010 & \bf 2 & 1010 & \bf A\\ + 011 & \bf 3 & 0011 & \bf 3 & 1011 & \bf B\\[\smallskipamount] + 100 & \bf 4 & 0100 & \bf 4 & 1100 & \bf C\\ + 101 & \bf 5 & 0101 & \bf 5 & 1101 & \bf D\\ + 110 & \bf 6 & 0110 & \bf 6 & 1110 & \bf E\\ + 111 & \bf 7 & 0111 & \bf 7 & 1111 & \bf F\\ + \end{tabular} + + \medskip + + \begin{itemize} + \item + Oktal- und Hexadezimalzahlen lassen sich ziffernweise\\ + in Binär-Zahlen umrechnen. + \item + Hexadezimalzahlen sind eine Kurzschreibweise für Binärzahlen,\\ + gruppiert zu jeweils 4 Bits. + \item + Oktalzahlen sind eine Kurzschreibweise für Binärzahlen,\\ + gruppiert zu jeweils 3 Bits. + \item + Trotz Taschenrechner u.\,ä.\ lohnt es sich,\\ + die o.\,a.\ Umrechnungstabelle \textbf{auswendig} zu kennen. + \end{itemize} + +\end{frame} + +\subsubsection{Bit-Operationen in C} + +\begin{frame}[fragile] + + \showsubsubsection + + \begin{tabular}{lll} + C-Operator & Verknüpfung & Anwendung \\[\smallskipamount] + \lstinline,&, & Und & Bits gezielt löschen \\ + \lstinline,|, & Oder & Bits gezielt setzen \\ + \lstinline,^, & Exklusiv-Oder & Bits gezielt invertieren \\ + \lstinline,~, & Nicht & Alle Bits invertieren \\[\smallskipamount] + \lstinline,<<, & Verschiebung nach links & Maske generieren \\ + \lstinline,>>, & Verschiebung nach rechts & Bits isolieren + \end{tabular} + + \bigskip + + Numerierung der Bits: von rechts ab 0 + + \medskip + + \begin{tabular}{ll} + Bit Nr.\ 3 auf 1 setzen: & + \lstinline,a |= 1 << 3;, \\ + Bit Nr.\ 4 auf 0 setzen: & + \lstinline,a &= ~(1 << 4);, \\ + Bit Nr.\ 0 invertieren: & + \lstinline,a ^= 1 << 0;, + \end{tabular} + + \smallskip + + ~~Abfrage, ob Bit Nr.\ 1 gesetzt ist:\quad + \lstinline{if (a & (1 << 1))} + +\end{frame} + +\nosectionnonumber{Aufgabe} + +\begin{frame}[fragile] + + \shownosectionnonumber + + Schreiben Sie C-Funktionen, die ein "`Array von Bits"' realisieren, z.\,B. + + \smallskip + + \begin{tabular}[t]{ll} + \lstinline|void set_bit (int i);| & Bei Index $i$ auf 1 setzen \\ + \lstinline|void clear_bit (int i);| & Bei Index $i$ auf 0 setzen \\ + \lstinline|int get_bit (int i);| & Bei Index $i$ lesen + \end{tabular} + + \medskip + + Hinweise: + \begin{itemize} + \item + Die Größe des Bit-"`Arrays"' (z.\,B.\ 1000) dürfen Sie als \emph{vorher bekannt\/} voraussetzen. + \item + Sie benötigen ein Array, z.\,B.\ von \lstinline|char|- oder \lstinline|int|-Variablen. + \item + Sie benötigen eine Division (\lstinline|/|) sowie den Divisionsrest (Modulo: \lstinline|%|). + \end{itemize} + + \bigskip + + Diese Aufgabe berührt die Themen + "`Umgang mit Arrays und Zeigern"', "`Bit-Manipulation"' + und je nach Implementierung auch "`objektorientierte Programmierung"'. + Dies zu begründen, ist Teil der Aufgabe. + +\end{frame} + +\addtocounter{subsection}{1} + +\subsection{Interrupts} + +\begin{frame}[fragile] + + \showsubsection + + Externes Gerät ruft (per Stromsignal) Unterprogramm auf + + Zeiger hinterlegen: "`Interrupt-Vektor"' + + Beispiel: eingebaute Uhr\hfill + \makebox(0,0)[tr]{% + \only<1->{\begin{minipage}[t]{4.7cm} + \vspace*{-0.3cm}% + statt Zählschleife (\lstinline{_delay_ms}):\\ + Hauptprogramm kann\\ + andere Dinge tun + \end{minipage}}% + } + + \medskip + + \begin{lstlisting} + #include <avr/interrupt.h> + + ... + + + ISR (TIMER0B_COMP_vect) + { + PORTD ^= 0x40; + } + \end{lstlisting} + \begin{picture}(0,0) + \color{red} + \put(1.9,3.1){\makebox(0,0)[tr]{\tikz{\draw[-latex](0,0)--(-1.4,-1.0);}}} + \put(2.0,3.2){\makebox(0,0)[l]{"`Dies ist ein Interrupt-Handler."'}} + \put(2.3,2.6){\makebox(0,0)[tr]{\tikz{\draw[-latex](0,0)--(-0.6,-0.55);}}} + \put(2.4,2.6){\makebox(0,0)[l]{Interrupt-Vektor darauf zeigen lassen}} + \end{picture} + + Initialisierung über spezielle Ports: + \lstinline{TCCR0B}, \lstinline{TIMSK0} + + \bigskip + + \emph{Details: siehe Datenblatt und Schaltplan} + + \vspace*{-2.5cm}\hfill + {\color{red}Herstellerspezifisch!}% + \hspace*{1cm} + +\end{frame} + +\begin{frame}[fragile] + + \showsubsection + + Externes Gerät ruft (per Stromsignal) Unterprogramm auf + + Zeiger hinterlegen: "`Interrupt-Vektor"' + + Beispiel: Taster\hfill + \makebox(0,0)[tr]{% + \begin{minipage}[t]{4.7cm} + \vspace*{-0.3cm}% + statt \newterm{Busy Waiting\/}:\\ + Hauptprogramm kann\\ + andere Dinge tun + \end{minipage}} + + \medskip + + \begin{lstlisting} + #include <avr/interrupt.h> + ... + + ISR (INT0_vect) + { + PORTD ^= 0x40; + } + \end{lstlisting} + + \medskip + + Initialisierung über spezielle Ports: + \lstinline{EICRA}, \lstinline{EIMSK} + + \bigskip + + \emph{Details: siehe Datenblatt und Schaltplan} + + \vspace*{-2.5cm}\hfill + {\color{red}Herstellerspezifisch!}% + \hspace*{1cm} + +\end{frame} + +\subsection{volatile-Variable} + +\begin{frame}[fragile] + + \showsubsection + + Externes Gerät ruft (per Stromsignal) Unterprogramm auf + + Zeiger hinterlegen: "`Interrupt-Vektor"' + + Beispiel: Taster + + \vspace*{-2.5pt} + + \begin{minipage}[t]{5cm} + \begin{onlyenv}<1> + \begin{lstlisting}[gobble=8] + ¡#include <avr/interrupt.h> + ... + + uint8_t key_pressed = 0; + + ISR (INT0_vect) + { + key_pressed = 1; + }¿ + \end{lstlisting} + \end{onlyenv} + \begin{onlyenv}<2> + \begin{lstlisting}[gobble=8] + ¡#include <avr/interrupt.h> + ... + + volatile uint8_t key_pressed = 0; + + ISR (INT0_vect) + { + key_pressed = 1; + }¿ + \end{lstlisting} + \end{onlyenv} + \end{minipage}\hfill + \begin{minipage}[t]{6cm} + \begin{lstlisting}[gobble=6] + ¡int main (void) + { + ... + + while (1) + { + while (!key_pressed) + ; /* just wait */ + PORTD ^= 0x40; + key_pressed = 0; + } + return 0; + }¿ + \end{lstlisting} + \end{minipage} + + \pause + \begin{picture}(0,0) + \color{red} + \put(10.3,4.0){\makebox(0,0)[b]{\begin{minipage}{6cm} + \begin{center} + \textbf{volatile}:\\ + Speicherzugriff\\ + nicht wegoptimieren + \end{center} + \end{minipage}}} + \put(10.3,3.95){\makebox(0,0)[tr]{\tikz{\draw[-latex](0,0)--(-0.5,-0.9);}}} + \end{picture} + +\end{frame} + +\begin{frame}[fragile] + + \showsubsection + + Was ist eigentlich \lstinline{PORTD}? + + \bigskip +% \pause + + \lstinline[style=cmd]{avr-gcc -Wall -Os -mmcu=atmega328p blink-3.c -E} + + \bigskip +% \pause + \lstinline{PORTD = 0x01;}\\ + \textarrow\quad + \lstinline[style=terminal]{(*(volatile uint8_t *)((0x0B) + 0x20)) = 0x01;}\\ +% \pause + \begin{picture}(0,2)(0,-1.7) + \color{red} + \put(5.75,0.3){$\underbrace{\rule{2.95cm}{0pt}}_{\mbox{Zahl: \lstinline|0x2B|}}$} +% \pause + \put(1.55,0.3){$\underbrace{\rule{4.0cm}{0pt}}_{\mbox{\shortstack[t]{Umwandlung in Zeiger\\ + auf \lstinline|volatile uint8_t|}}}$} +% \pause + \put(1.32,-1){\makebox(0,0)[b]{\tikz{\draw[-latex](0,0)--(0,1.3)}}} + \put(1.12,-1.1){\makebox(0,0)[tl]{Dereferenzierung des Zeigers}} + \end{picture} + +% \pause + \textarrow\quad + \lstinline|volatile uint8_t|-Variable an Speicheradresse \lstinline|0x2B| + +% \pause + \bigskip + \bigskip + + \textarrow\quad + \lstinline|PORTA = PORTB = PORTC = PORTD = 0| ist eine schlechte Idee. + +\end{frame} + +\subsection{Byte-Reihenfolge -- Endianness} +\subsubsection{Konzept} + +\begin{frame}[fragile] + + \showsubsection + \showsubsubsection + + Eine Zahl geht über mehrere Speicherzellen.\\ + Beispiel: 16-Bit-Zahl in 2 8-Bit-Speicherzellen + + \smallskip + + Welche Bits liegen wo? + +% \pause + \bigskip + + $1027 = 1024 + 2 + 1 = 0000\,0100\,0000\,0011_2 = 0403_{16}$ + +% \pause + \bigskip + Speicherzellen: + + \medskip + \begin{tabular}{|c|c|l}\cline{1-2} + \raisebox{-0.25ex}{04} & \raisebox{-0.25ex}{03} & \strut Big-Endian "`großes Ende zuerst"' \\\cline{1-2} + \multicolumn{2}{c}{} & für Menschen leichter lesbar \\ + \multicolumn{3}{c}{} \\[-5pt]\cline{1-2} + \raisebox{-0.25ex}{03} & \raisebox{-0.25ex}{04} & \strut Little-Endian "`kleines Ende zuerst"' \\\cline{1-2} + \multicolumn{2}{c}{} & bei Additionen effizienter + \end{tabular} + +% \pause + \medskip + \textarrow\ Geschmackssache +% \pause\\ + \quad\textbf{\dots\ außer bei Datenaustausch!} + +% \pause +% \bigskip +% +% Aber: nicht verwechseln! \qquad $0304_{16} = 772$ + +\end{frame} + +\begin{frame} + + \showsubsection + \showsubsubsection + + Eine Zahl geht über mehrere Speicherzellen.\\ + Beispiel: 16-Bit-Zahl in 2 8-Bit-Speicherzellen + + \smallskip + + Welche Bits liegen wo? + + \medskip + + \textarrow\ Geschmackssache\\ + \textbf{\dots\ außer bei Datenaustausch!} + + \begin{itemize} + \item + Dateiformate + \item + Datenübertragung + \end{itemize} + +\end{frame} + +\subsubsection{Dateiformate} + +\begin{frame} + + \showsubsection + \showsubsubsection + + Audio-Formate: Reihenfolge der Bytes in 16- und 32-Bit-Zahlen + \begin{itemize} + \item + RIFF-WAVE-Dateien (\file{.wav}): Little-Endian + \item + Au-Dateien (\file{.au}): Big-Endian +% \pause + \item + ältere AIFF-Dateien (\file{.aiff}): Big-Endian + \item + neuere AIFF-Dateien (\file{.aiff}): Little-Endian + \end{itemize} + +% \pause + \bigskip + + Grafik-Formate: Reihenfolge der Bits in den Bytes + \begin{itemize} + \item + PBM-Dateien: Big-Endian\only<1->{, MSB first} + \item + XBM-Dateien: Little-Endian\only<1->{, LSB first} + \end{itemize} + \only<1->{MSB/LSB = most/least significant bit} + + \smallskip + + Verwechselungsgefahr: most/least significant byte + +\end{frame} + +\subsubsection{Datenübertragung} + +\begin{frame} + + \showsubsection + \showsubsubsection + + \begin{itemize} + \item + RS-232 (serielle Schnittstelle): LSB first + \item + I$^2$C: MSB first + \item + USB: beides +% \pause + \medskip + \item + Ethernet: LSB first + \item + TCP/IP (Internet): Big-Endian + \end{itemize} + +\end{frame} + +\subsection{Binärdarstellung negativer Zahlen} + +\begin{frame}[fragile] + + \showsubsection + + Speicher ist begrenzt!\\ + \textarrow\ feste Anzahl von Bits + + \medskip + + 8-Bit-Zahlen ohne Vorzeichen: \lstinline{uint8_t}\\ + \textarrow\ Zahlenwerte von \lstinline{0x00} bis \lstinline{0xff} = 0 bis 255\\ +% \pause + \textarrow\ 255 + 1 = 0 + +% \pause + \medskip + + 8-Bit-Zahlen mit Vorzeichen: \lstinline{int8_t}\\ + \lstinline{0xff} = 255 ist die "`natürliche"' Schreibweise für $-1$.\\ +% \pause + \textarrow\ Zweierkomplement + +% \pause + \medskip + + Oberstes Bit = 1: negativ\\ + Oberstes Bit = 0: positiv\\ + \textarrow\ 127 + 1 = $-128$ + +\end{frame} + +\begin{frame}[fragile] + + \showsubsection + + Speicher ist begrenzt!\\ + \textarrow\ feste Anzahl von Bits + + \medskip + + 16-Bit-Zahlen ohne Vorzeichen: + \lstinline{uint16_t}\hfill\lstinline{uint8_t}\\ + \textarrow\ Zahlenwerte von \lstinline{0x0000} bis \lstinline{0xffff} + = 0 bis 65535\hfill 0 bis 255\\ + \textarrow\ 65535 + 1 = 0\hfill 255 + 1 = 0 + + \medskip + + 16-Bit-Zahlen mit Vorzeichen: + \lstinline{int16_t}\hfill\lstinline{int8_t}\\ + \lstinline{0xffff} = 66535 ist die "`natürliche"' Schreibweise für $-1$.\hfill + \lstinline{0xff} = 255 = $-1$\\ + \textarrow\ Zweierkomplement + + \medskip + + Oberstes Bit = 1: negativ\\ + Oberstes Bit = 0: positiv\\ + \textarrow\ 32767 + 1 = $-32768$ + + \bigskip + Literatur: \url{http://xkcd.com/571/} + +\end{frame} + +\begin{frame}[fragile] + + \showsubsection + + Frage: \emph{Für welche Zahl steht der Speicherinhalt\, + \raisebox{2pt}{% + \tabcolsep0.25em + \begin{tabular}{|c|c|}\hline + \rule{0pt}{11pt}a3 & 90 \\\hline + \end{tabular}} + (hexadezimal)?} + +% \pause + \smallskip + Antwort: \emph{Das kommt darauf an.} ;--) + +% \pause + \medskip + Little-Endian: + + \smallskip + + \begin{tabular}{lrl} + als \lstinline,int8_t,: & $-93$ & (nur erstes Byte)\\ + als \lstinline,uint8_t,: & $163$ & (nur erstes Byte)\\ + als \lstinline,int16_t,: & $-28509$\\ + als \lstinline,uint16_t,: & $37027$\\ + \lstinline,int32_t, oder größer: & $37027$ + & (zusätzliche Bytes mit Nullen aufgefüllt) + \end{tabular} + +% \pause + \medskip + Big-Endian: + + \smallskip + + \begin{tabular}{lrl} + als \lstinline,int8_t,: & $-93$ & (nur erstes Byte)\\ + als \lstinline,uint8_t,: & $163$ & (nur erstes Byte)\\ + als \lstinline,int16_t,: & $-23664$\\ + als \lstinline,uint16_t,: & $41872$\\ als \lstinline,int32_t,: & $-1550843904$ & (zusätzliche Bytes\\ + als \lstinline,uint32_t,: & $2744123392$ & mit Nullen aufgefüllt)\\ + als \lstinline,int64_t,: & $-6660823848880963584$\\ + als \lstinline,uint64_t,: & $11785920224828588032$\\ + \end{tabular} + + \vspace*{-1cm} + +\end{frame} + +\subsection{Speicherausrichtung -- Alignment} + +\begin{frame}[fragile] + + \showsubsection + + \begin{lstlisting} + #include <stdint.h> + + uint8_t a; + uint16_t b; + uint8_t c; + \end{lstlisting} + +% \pause + \bigskip + + Speicheradresse durch 2 teilbar -- "`16-Bit-Alignment"' + \begin{itemize} + \item + 2-Byte-Operation: effizienter +% \pause + \item + \dots\ oder sogar nur dann erlaubt +% \pause + \arrowitem + Compiler optimiert Speicherausrichtung + \end{itemize} + + \medskip + +% \pause + \begin{minipage}{3cm} + \begin{lstlisting}[gobble=6] + ¡uint8_t a; + uint8_t dummy; + uint16_t b; + uint8_t c;¿ + \end{lstlisting} + \end{minipage} +% \pause + \begin{minipage}{3cm} + \begin{lstlisting}[gobble=6] + ¡uint8_t a; + uint8_t c; + uint16_t b;¿ + \end{lstlisting} + \end{minipage} + +% \pause + \vspace{-1.75cm} + \strut\hfill + \begin{minipage}{6.5cm} + Fazit: + \begin{itemize} + \item + \textbf{Adressen von Variablen\\ + sind systemabhängig} + \item + Bei Definition von Datenformaten\\ + Alignment beachten \textarrow\ effizienter + \end{itemize} + \end{minipage} + +\end{frame} + +\nosectionnonumber{\inserttitle} + +\begin{frame} + + \shownosectionnonumber + + \begin{itemize} + \item[\textbf{1}] \textbf{Einführung} + \hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp}}} + \item[\textbf{2}] \textbf{Einführung in C} + \item[\textbf{3}] \textbf{Bibliotheken} + \item[\textbf{4}] \textbf{Algorithmen} + \item[\textbf{5}] \textbf{Hardwarenahe Programmierung} + \begin{itemize} + \item[5.1] Bit-Operationen + \item[5.2] I/O-Ports + \color{medgreen} + \item[5.3] Interrupts + \item[5.4] volatile-Variable + \item[5.6] Byte-Reihenfolge -- Endianness + \item[5.7] Binärdarstellung negativer Zahlen + \item[5.8] Speicherausrichtung -- Alignment + \end{itemize} + \item[\textbf{6}] \textbf{Objektorientierte Programmierung} + \begin{itemize} + \color{red} + \item[6.0] Dynamische Speicherverwaltung + \item[6.1] Konzepte und Ziele + \vspace*{-\smallskipamount} + \item[\dots] +% \item[6.2] Beispiel: Zahlen und Buchstaben +% \color{red} +% \item[6.3] Unions +% \item[6.4] Virtuelle Methoden +% \color{black} +% \item[6.5] Beispiel: Graphische Benutzeroberfläche (GUI) +% \item[6.6] Ausblick: C++ + \end{itemize} + \item[\textbf{7}] \textbf{Datenstrukturen} + \vspace*{-1cm} + \end{itemize} + +\end{frame} + +\section{Objektorientierte Programmierung} + +\addtocounter{subsection}{-1} +\subsection{Dynamische Speicherverwaltung} + +\begin{frame}[fragile] + + \showsection + \showsubsection + + \begin{itemize} + \item + Array: feste Anzahl von Elementen desselben Typs (z.\,B.\ 3 ganze Zahlen) + \item + Dynamisches Array: variable Anzahl von Elementen desselben Typs + \end{itemize} + + \bigskip + + \begin{lstlisting} + char *name[] = { "Anna", "Berthold", "Caesar" }; + + ... + + name[3] = "Dieter"; + \end{lstlisting} + + \begin{picture}(0,0) + \color{red} + \put(0,0){\line(3,1){3.5}} + \put(0,1){\line(3,-1){3.5}} + \end{picture} + +\end{frame} + +\begin{frame}[fragile] + + \showsection + \showsubsection + + \bigskip + + \begin{lstlisting} + #include <stdlib.h> + + ... + + char **name = malloc (3 * sizeof (char *)); + /* Speicherplatz für 3 Zeiger anfordern */ + + ... + + free (name) + /* Speicherplatz freigeben */ + + \end{lstlisting} + +\end{frame} + +\subsection{Konzepte und Ziele} + +\begin{frame} + + \showsection + \showsubsection + + \begin{itemize} + \item +% Array: feste Anzahl von Elementen desselben Typs (z.\,B.\ 3 ganze Zahlen) + Array: Elemente desselben Typs (z.\,B.\ 3 ganze Zahlen) +% \item +% Dynamisches Array: variable Anzahl von Elementen desselben Typs + \item + Problem: Elemente unterschiedlichen Typs + \item + Lösung: den Typ des Elements zusätzlich speichern \textarrow\ \newterm{Objekt} + \item + Problem: Die Elemente sind unterschiedlich groß (Speicherplatz). + \item + Lösung: Im Array nicht die Objekte selbst speichern, sondern Zeiger darauf. + \end{itemize} + \begin{itemize} + \item + Funktionen, die mit dem Objekt arbeiten: \newterm{Methoden} + \begin{onlyenv}<1> + \item + Was die Funktion bewirkt,\\ + hängt vom Typ des Objekts ab + \item + Realisierung über endlose \lstinline{if}-Ketten + \end{onlyenv} + \begin{onlyenv}<2> + \item + Was die Funktion bewirkt + \begin{picture}(0,0) + \color{red} + \put(-4.00,-0.05){\tikz{\draw[thick](0,0.25)--(3.75,-0.05);% + \draw[thick](-0.1,-0.05)--(3.75,0.3);}} + \end{picture}% + Welche Funktion aufgerufen wird,\\ + hängt vom Typ des Objekts ab: \newterm{virtuelle Methode} + \item + Realisierung über endlose \lstinline{if}-Ketten% + \begin{picture}(0,0) + \color{red} + \put(-2.75,-0.05){\tikz{\draw[thick](0,0.25)--(2.5,-0.05);% + \draw[thick](-0.1,-0.05)--(2.5,0.3);}} + \put(1.5,-1.1){\begin{rotate}{7}\large\bf\textarrow\ + kommt gleich +% nächste Woche + \end{rotate}} + \end{picture} + Zeiger, die im Objekt gespeichert sind\\ + (Genaugenommen: Tabelle von Zeigern) + \end{onlyenv} + \end{itemize} + +\end{frame} + +\begin{frame} + + \showsection + \showsubsection + + \begin{itemize} + \item + Problem: Elemente unterschiedlichen Typs + \item + Lösung: den Typ des Elements zusätzlich speichern \textarrow\ \newterm{Objekt} + \item + \newterm{Methoden\/} und \newterm{virtuelle Methoden} + \end{itemize} + + \begin{itemize} + \item + Zeiger auf verschiedene Strukturen\\ + mit einem gemeinsamen Anteil von Datenfeldern\\ + \textarrow\ "`verwandte"' \newterm{Objekte}, \newterm{Klassen} von Objekten + \item + Struktur, die \emph{nur\/} den gemeinsamen Anteil enthält\\ + \textarrow\ "`Vorfahr"', \newterm{Basisklasse}, \newterm{Vererbung} + \item +% Explizite Typumwandlung eines Zeigers auf die Basisklasse\\ +% in einen Zeiger auf die \newterm{abgeleitete Klasse}\\ +% \textarrow\ Man kann ein Array unterschiedlicher Objekte\\ +% \strut\phantom{\textarrow} in einer Schleife abarbeiten.\\ + Zeiger auf die Basisklasse dürfen auf Objekte\\ + der \newterm{abgeleiteten Klasse} zeigen\\ + \textarrow\ \newterm{Polymorphie} + \end{itemize} + +\end{frame} + +\subsection{Beispiel: Zahlen und Buchstaben} + +\begin{frame}[fragile] + + \showsection + \showsubsection + + \begin{center} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + int type; + } t_base;¿ + \end{lstlisting} + \end{minipage}\\[0.5cm] + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + int type; + int content; + } t_integer;¿ + \end{lstlisting} + \end{minipage} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + int type; + char *content; + } t_string;¿ + \end{lstlisting} + \end{minipage} + \end{center} + +\end{frame} + +\begin{frame}[fragile] + \begin{center} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + int type; + } t_base;¿ + \end{lstlisting} + \end{minipage}\\[0.5cm] + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + int type; + int content; + } t_integer;¿ + \end{lstlisting} + \end{minipage} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + int type; + char *content; + } t_string;¿ + \end{lstlisting} + \end{minipage}\\[0.7cm] + \begin{onlyenv}<1> + \begin{minipage}{8cm} + \begin{lstlisting}[gobble=10] + ¡t_integer i = { 1, 42 }; + t_string s = { 2, "Hello, world!" }; + + t_base *object[] = { (t_base *) &i, (t_base *) &s };¿ + \end{lstlisting} + \end{minipage}% + \begin{picture}(0,0) + \color{red} + \put(-5.4,-0.8){\mbox{$\underbrace{\rule{1.45cm}{0pt}}_{\shortstack{\strut explizite\\Typumwandlung}}$}} + \end{picture} + \end{onlyenv} +% \begin{onlyenv}<2> +% \begin{minipage}{5cm} +% \begin{lstlisting}[gobble=10] +% ¡typedef union +% { +% t_base base; +% t_integer integer; +% t_string string; +% } t_object;¿ +% \end{lstlisting} +% \end{minipage} +% \end{onlyenv} + \end{center} + +\end{frame} + +\subsection{Unions} + +\begin{frame}[fragile] + + \showsubsection + + Variable teilen sich denselben Speicherplatz. + + \medskip + + \begin{minipage}[t]{3.7cm} + \begin{lstlisting}[gobble=6] + ¡typedef union + { + int8_t i; + uint8_t u; + } num8_t;¿ + \end{lstlisting} + \end{minipage}% + \begin{minipage}[t]{4.5cm} + \begin{lstlisting}[gobble=6] + ¡int main (void) + { + num8_t test; + test.i = -1; + printf ("%d\n", test.u); + return 0; + }¿ + \end{lstlisting} + \end{minipage} + +\end{frame} + +\begin{frame}[fragile] + + \showsubsection + + Variable teilen sich denselben Speicherplatz. + + \medskip + + \begin{minipage}[t]{3.7cm} + \begin{lstlisting}[gobble=6] + ¡typedef union + { + char s[8]; + uint64_t x; + } num_char_t;¿ + \end{lstlisting} + \end{minipage}% + \begin{minipage}[t]{4.5cm} + \begin{lstlisting}[gobble=6] + ¡int main (void) + { + num_char_t test = { "Hello!" }; + printf ("%lx\n", test.x); + return 0; + }¿ + \end{lstlisting} + \end{minipage} + +\end{frame} + +\begin{frame}[fragile] + + \showsubsection + + Variable teilen sich denselben Speicherplatz. + + \medskip + + \begin{minipage}[t]{3.7cm} + \begin{lstlisting}[gobble=6] + ¡typedef union + { + t_base base; + t_integer integer; + t_string string; + } t_object;¿ + \end{lstlisting} + \end{minipage}% + \begin{minipage}[t]{3.0cm} + \begin{lstlisting}[gobble=6] + + ¡typedef struct + { + int type; + } t_base;¿ + \end{lstlisting} + \end{minipage}% + \begin{minipage}[t]{3.0cm} + \begin{lstlisting}[gobble=6] + + ¡typedef struct + { + int type; + int content; + } t_integer;¿ + \end{lstlisting} + \end{minipage}% + \begin{minipage}[t]{3.0cm} + \begin{lstlisting}[gobble=6] + + ¡typedef struct + { + int type; + char *content; + } t_string;¿ + \end{lstlisting} + \end{minipage} + + \bigskip + + \begin{center} + \begin{minipage}{8.5cm} + \begin{lstlisting}[gobble=8] + ¡if (this->base.type == T_INTEGER) + printf ("Integer: %d\n", this->integer.content); + else if (this->base.type == T_STRING) + printf ("String: \"%s\"\n", this->string.content);¿ + \end{lstlisting} + \end{minipage} + \end{center} + +\end{frame} + +\subsection{Virtuelle Methoden} + +\begin{frame}[fragile] + \showsubsection + + \begin{lstlisting} + void print_object (t_object *this) + { + if (this->base.type == T_INTEGER) + printf ("Integer: %d\n", this->integer.content); + else if (this->base.type == T_STRING) + printf ("String: \"%s\"\n", this->string.content); + } + \end{lstlisting} + + \begin{picture}(0,0) + \color{red} + \put(9,1.7){\shortstack[l]{if-Kette:\\\strut wird unübersichtlich}} + \put(1,-2){\mbox{\textarrow}} + \put(0,-3){\mbox{Zeiger auf Funktionen}} + \end{picture} + + \begin{lstlisting}[xleftmargin=4cm] + void print_integer (t_object *this) + { + printf ("Integer: %d\n", this->integer.content); + } + + void print_string (t_object *this) + { + printf ("String: \"%s\"\n", this->string.content); + } + \end{lstlisting} + +\end{frame} + +\begin{frame}[fragile] + \showsubsection + + Zeiger auf Funktionen + + \medskip + + \begin{lstlisting} + void (* print) (t_object *this); + \end{lstlisting} + \begin{picture}(0,1.2)(0,-0.9) + \color{red} + \put(0.95,0.3){\mbox{$\underbrace{\rule{1cm}{0pt}}$}} + \put(0.2,-0.7){\shortstack{das, worauf print zeigt,\\ist eine Funktion}} + \end{picture} + + \begin{itemize} + \item + Objekt enthält Zeiger auf Funktion + \begin{onlyenv}<1> + \medskip + \begin{lstlisting}[gobble=10] + typedef struct + { + void (* print) (union t_object *this); + int content; + } t_integer; + \end{lstlisting} + \end{onlyenv} + \begin{onlyenv}<2-> + \vspace*{-3.5cm} % Why doesn't a picture environment work here??? :-( + \begin{lstlisting}[gobble=10,xleftmargin=5.5cm] + typedef struct + { + void (* print) (union t_object *this); + int content; + } t_integer; + \end{lstlisting} + \vspace*{0.85cm} + \bigskip + \smallskip + \end{onlyenv} + \pause + \item + Konstruktor initialisiert diesen Zeiger + \begin{onlyenv}<2> + \medskip + \begin{lstlisting}[gobble=10] + t_object *new_integer (int i) + { + t_object *p = malloc (sizeof (t_integer)); + p->integer.print = print_integer; + p->integer.content = i; + return p; + } + \end{lstlisting} + \vspace*{-2cm} + \end{onlyenv} + \pause + \item + Aufruf: "`automatisch"' die richtige Funktion + \begin{onlyenv}<3> + \medskip + \begin{lstlisting}[gobble=10] + for (int i = 0; object[i]; i++) + object[i]->base.print (object[i]); + \end{lstlisting} + \end{onlyenv} + \pause + \medskip + \item + in größeren Projekten:\\ + Objekt enthält Zeiger auf Tabelle von Funktionen + \end{itemize} +\end{frame} + +\subsection{Beispiel: Graphische Benutzeroberfläche (GUI)} + +\begin{frame}[fragile] + + \showsubsection + + \scriptsize + \begin{lstlisting} + #include <gtk/gtk.h> + + int main (int argc, char **argv) + { + gtk_init (&argc, &argv); + GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), "Hello"); + g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); + GtkWidget *vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 10); + GtkWidget *label = gtk_label_new ("Hello, world!"); + gtk_container_add (GTK_CONTAINER (vbox), label); + GtkWidget *button = gtk_button_new_with_label ("Quit"); + g_signal_connect (button, "clicked", G_CALLBACK (gtk_main_quit), NULL); + gtk_container_add (GTK_CONTAINER (vbox), button); + gtk_widget_show (button); + gtk_widget_show (label); + gtk_widget_show (vbox); + gtk_widget_show (window); + gtk_main (); + return 0; + } + \end{lstlisting} + + \vspace*{-6cm}\strut\hfill + \includegraphics[scale=0.85]{hello-gtk.png}\\[2cm] + \begin{flushright} + \normalsize\bf Praktikumsversuch:\\ + Objektorientiertes Zeichenprogramm + \end{flushright} + +\end{frame} + +\subsection{Ausblick: C++} + +\begin{frame}[fragile] + \showsubsection + + \begin{center} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + void (* print) (union t_object *this); + } t_base;¿ + \end{lstlisting} + \end{minipage}\\[0.5cm] + \begin{minipage}{5.5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + void (* print) (...); + int content; + } t_integer;¿ + \end{lstlisting} + \end{minipage} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡typedef struct + { + void (* print) (union t_object *this); + char *content; + } t_string;¿ + \end{lstlisting} + \end{minipage} + \end{center} + +\end{frame} + +\begin{frame}[fragile] + \showsubsection + + \begin{center} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡struct TBase + { + virtual void print (void); + };¿ + \end{lstlisting} + \end{minipage}\\[0.5cm] + \begin{minipage}{5.5cm} + \begin{lstlisting}[gobble=8] + ¡struct TInteger: public TBase + { + virtual void print (void); + int content; + };¿ + \end{lstlisting} + \end{minipage} + \begin{minipage}{5cm} + \begin{lstlisting}[gobble=8] + ¡struct TString: public TBase + { + virtual void print (void); + char *content; + };¿ + \end{lstlisting} + \end{minipage} + \end{center} + +\end{frame} + +\nosectionnonumber{\inserttitle} + +\begin{frame} + + \shownosectionnonumber + + \begin{itemize} + \item[\textbf{1}] \textbf{Einführung} + \hfill\makebox(0,0)[br]{\raisebox{2.25ex}{\url{https://gitlab.cvh-server.de/pgerwinski/hp}}} + \item[\textbf{2}] \textbf{Einführung in C} + \item[\textbf{3}] \textbf{Bibliotheken} + \item[\textbf{4}] \textbf{Algorithmen} + \item[\textbf{5}] \textbf{Hardwarenahe Programmierung} + \item[\textbf{6}] \textbf{Objektorientierte Programmierung} + \begin{itemize} + \color{medgreen} + \item[6.0] Dynamische Speicherverwaltung + \item[6.1] Konzepte und Ziele + \item[6.2] Beispiel: Zahlen und Buchstaben + \item[6.3] Unions + \item[6.4] Virtuelle Methoden + \item[6.5] Beispiel: Graphische Benutzeroberfläche (GUI) + \item[6.6] Ausblick: C++ + \end{itemize} + \item[\textbf{7}] \textbf{Datenstrukturen} + \vspace*{-1cm} + \end{itemize} + +\end{frame} + +\end{document} diff --git a/20210128/hp-musterloesung-20210128.pdf b/20210128/hp-musterloesung-20210128.pdf new file mode 100644 index 0000000000000000000000000000000000000000..05884e3ee698a07f1924d6b18f57a8c29c7374e9 Binary files /dev/null and b/20210128/hp-musterloesung-20210128.pdf differ diff --git a/20210128/hp-musterloesung-20210128.tex b/20210128/hp-musterloesung-20210128.tex new file mode 100644 index 0000000000000000000000000000000000000000..93131492c646f3186f1715c1f7e4bf4a1bb23b88 --- /dev/null +++ b/20210128/hp-musterloesung-20210128.tex @@ -0,0 +1,763 @@ +% hp-musterloesung-20210128.pdf - Solutions to the Exercises on Low-Level Programming +% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Peter Gerwinski +% +% This document is free software: you can redistribute it and/or +% modify it either under the terms of the Creative Commons +% Attribution-ShareAlike 3.0 License, or under the terms of the +% GNU General Public License as published by the Free Software +% Foundation, either version 3 of the License, or (at your option) +% any later version. +% +% This document is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this document. If not, see <http://www.gnu.org/licenses/>. +% +% You should have received a copy of the Creative Commons +% Attribution-ShareAlike 3.0 Unported License along with this +% document. If not, see <http://creativecommons.org/licenses/>. + +% README: Speicherformate von Zahlen, Personen-Datenbank, objektorientierte Tier-Datenbank + +\documentclass[a4paper]{article} + +\usepackage{pgscript} + +\begin{document} + + \section*{Hardwarenahe Programmierung\\ + Musterlösung zu den Übungsaufgaben -- 28.\ Januar 2021} + + \exercise{Speicherformate von Zahlen} + + Wir betrachten das folgende Programm (\gitfile{hp}{2020ws/20210128}{aufgabe-1.c}): + \begin{lstlisting} + #include <stdio.h> + #include <stdint.h> + + typedef struct + { + uint32_t a; + uint64_t b; + uint8_t c; + } three_numbers; + + int main (void) + { + three_numbers xyz = { 1819042120, 2410670883059281007, 0 }; + printf ("%s\n", &xyz); + return 0; + } + \end{lstlisting} + + Das Programm wird für einen 32-Bit-Rechner compiliert und ausgeführt.\\ + (Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m32} sorgt dafür, + daß \lstinline[style=cmd]{gcc} Code für einen 32-Bit-Prozessor erzeugt.) + + \begin{lstlisting}[style=terminal] + $ ¡gcc -Wall -m32 aufgabe-2.c -o aufgabe-2¿ + aufgabe-2.c: In function "main": + aufgabe-2.c:14:13: warning: format "%s" expects argument of type "char *", but + argument 2 has type "three_numbers * {aka struct <anonymous> *}" [-Wformat=] + printf ("%s\n", &xyz); + ^ + $ ¡./aufgabe-2¿ + Hallo, Welt! + \end{lstlisting} + + \begin{enumerate}[\quad(a)] + \item + Erklären Sie die beim Compilieren auftretende Warnung. + \points{2} + \item + Erklären Sie die Ausgabe des Programms. + \points{4} + \item + Welche Endianness hat der verwendete Rechner? + Wie sähe die Ausgabe auf einem Rechner mit entgegengesetzter Endianness aus? + \points{2} + \item + Dasselbe Programm wird nun für einen 64-Bit-Rechner compiliert und ausgeführt.\\ + (Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m64} sorgt dafür, + daß \lstinline[style=cmd]{gcc} Code für einen 64-Bit-Prozessor erzeugt.) + \begin{lstlisting}[style=terminal,gobble=8] + $ ¡gcc -Wall -m64 aufgabe-2.c -o aufgabe-2¿ + aufgabe-2.c: In function "main": + aufgabe-2.c:14:13: warning: format "%s" expects argument of type "char *", + but argument 2 has type "three_numbers * {aka struct <anonymous> *}" + [-Wformat=] + printf ("%s\n", &xyz); + ^ + $ ¡./aufgabe-2¿ + Hall5V + \end{lstlisting} + (Es ist möglich, daß die konkrete Ausgabe auf Ihrem Rechner anders aussieht.)\par + Erklären Sie die geänderte Ausgabe des Programms. + \points{3} + \end{enumerate} + + \solution + + \begin{enumerate}[\quad(a)] + \item + \textbf{Erklären Sie die beim Compilieren auftretende Warnung.} + + Die Funktion \lstinline{printf()} mit der Formatspezifikation \lstinline{%s} + erwartet als Parameter einen String, d.\,h.\ einen Zeiger auf \lstinline{char}. + Die Adresse (\lstinline{&}) der Variablen \lstinline{xyz} + ist zwar ein Zeiger, aber nicht auf \lstinline{char}, + sondern auf einen \lstinline{struct} vom Typ \lstinline{three_numbers}. + Eine implizite Umwandlung des Zeigertyps ist zwar möglich, + aber normalerweise nicht das, was man beabsichtigt. + + \item + \textbf{Erklären Sie die Ausgabe des Programms.} + + Ein String in C ist ein Array von \lstinline{char}s + bzw.\ ein Zeiger auf \lstinline{char}. + Da die Funktion \lstinline{printf()} mit der Formatspezifikation \lstinline{%s} + einen String erwartet, wird sie das, worauf der übergebene Zeiger zeigt, + als ein Array von \lstinline{char}s interpretieren. + Ein \lstinline{char} entspricht einer 8-Bit-Speicherzelle. + Um die Ausgabe des Programms zu erklären, müssen wir daher + die Speicherung der Zahlen in den einzelnen 8-Bit-Speicherzellen betrachten. + + Hierfür wandeln wir zunächst die Zahlen von Dezimal nach Hexadezimal um. + Sofern nötig (hier nicht der Fall) füllen wir von links mit Nullen auf, + um den gesamten von der Variablen belegten Speicherplatz zu füllen + (hier: 32 Bit, 64 Bit, 8 Bit). + Jeweils 2 Hex-Ziffern stehen für 8 Bit. + \begin{center} + \begin{tabular}{rcl} + dezimal & & hexadezimal \\[\smallskipamount] + 1\,819\,042\,120 & = & 6C\,6C\,61\,48 \\ + 2\,410\,670\,883\,059\,281\,007 & = & 21\,74\,6C\,65\,57\,20\,2C\,6F \\ + 0 & = & 00 + \end{tabular} + \end{center} + Die Anordnung dieser 8-Bit-Zellen im Speicher lautet + \textbf{auf einem Big-Endian-Rechner} wie folgt: + \begin{center} + \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|}\hline + \raisebox{0.5ex}{\strut} + 6C & 6C & 61 & 48 & + 21 & 74 & 6C & 65 & 57 & 20 & 2C & 6F & + 00 + \\\hline + \end{tabular}\\[-4.2ex] + \kern1.7em% + $\underbrace{\rule{9.8em}{0pt}}_{\mbox{\lstinline{a}}}$\kern1pt% + $\underbrace{\rule{18.8em}{0pt}}_{\mbox{\lstinline{b}}}$\kern1pt% + $\underbrace{\rule{2.2em}{0pt}}_{\mbox{\lstinline{c}}}$% + \end{center} + \textbf{Auf einem Little-Endian-Rechner} lautet sie hingegen: + \begin{center} + \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|}\hline +% \raisebox{0.5ex}{\strut} +% H & a & l & l & +% o & , & & W & e & l & t & ! & \\\hline + \raisebox{0.5ex}{\strut} + 48 & 61 & 6C & 6C & + 6F & 2C & 20 & 57 & 65 & 6C & 74 & 21 & + 00 + \\\hline + \end{tabular}\\[-4.2ex] + \kern1.7em% + $\underbrace{\rule{9.8em}{0pt}}_{\mbox{\lstinline{a}}}$\kern1pt% + $\underbrace{\rule{18.8em}{0pt}}_{\mbox{\lstinline{b}}}$\kern1pt% + $\underbrace{\rule{2.2em}{0pt}}_{\mbox{\lstinline{c}}}$% + \end{center} + Anhand einer ASCII-Tabelle erkennt man, + daß die Big-Endian-Variante dem String \lstinline{"llaH!tleW ,o"} + und die Little-Endian-Variante dem String \lstinline{"Hallo, Welt!"} + entspricht -- jeweils mit einem Null-Symbol am Ende, + das von der Variablen \lstinline{c} herrührt. + + Auf einem Little-Endian-Rechner wird daher + \lstinline[style=terminal]{Hallo, Welt!} ausgegeben. + + \item + \textbf{Welche Endianness hat der verwendete Rechner?} + + Little-Endian (Begründung siehe oben) + + \textbf{Wie sähe die Ausgabe auf einem Rechner mit entgegengesetzter Endianness aus?} + + \lstinline[style=terminal]{llaH!tleW ,o} (Begründung siehe oben) + + \item + \textbf{Dasselbe Programm wird nun für einen 64-Bit-Rechner compiliert und ausgeführt.\\ + (Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m64} sorgt dafür, + daß \lstinline[style=cmd]{gcc} Code für einen 64-Bit-Prozessor erzeugt.)} + \begin{lstlisting}[style=terminal,gobble=8] + $ ¡gcc -Wall -m64 aufgabe-2.c -o aufgabe-2¿ + aufgabe-2.c: In function "main": + aufgabe-2.c:14:13: warning: format "%s" expects argument of type "char *", + but argument 2 has type "three_numbers * {aka struct <anonymous> *}" + [-Wformat=] + printf ("%s\n", &xyz); + ^ + $ ¡./aufgabe-2¿ + Hall5V + \end{lstlisting} + \textbf{(Es ist möglich, daß die konkrete Ausgabe auf Ihrem Rechner anders aussieht.)}\par + \textbf{Erklären Sie die geänderte Ausgabe des Programms.} + + \goodbreak + + Auf einem 64-Bit-Rechner hat eine 64-Bit-Variable + ein \textbf{64-Bit-Alignment}, + d.\,h.\ ihre Speicheradresse muß durch 8 teilbar sein. + + Der Compiler legt die Variablen daher wie folgt im Speicher ab (Little-Endian): + \begin{center} + \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|}\hline + \raisebox{0.5ex}{\strut} + 48 & 61 & 6C & 6C & ?? & ?? & ?? & ?? & + 6F & 2C & 20 & 57 & 65 & 6C & 74 & 21 & + 00 + \\\hline + \end{tabular}\\[-4.2ex] + \kern1.7em% + $\underbrace{\rule{9.8em}{0pt}}_{\mbox{\lstinline{a}}}$\kern1pt% + $\underbrace{\rule{9.1em}{0pt}}_{\mbox{Füll-Bytes}}$\kern1pt% + $\underbrace{\rule{18.8em}{0pt}}_{\mbox{\lstinline{b}}}$\kern1pt% + $\underbrace{\rule{2.2em}{0pt}}_{\mbox{\lstinline{c}}}$% + \end{center} + Der Inhalt der Füll-Bytes ist undefiniert. + Im Beispiel aus der Aufgabenstellung entsteht hier die Ausgabe + \lstinline[style=terminal]{5V}, was den (zufälligen) hexadezimalen Werten + 35 56 entspricht: + \begin{center} + \begin{tabular}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|}\hline + \raisebox{0.5ex}{\strut} + 48 & 61 & 6C & 6C & 35 & 56 & 00 & ?? & + 6F & 2C & 20 & 57 & 65 & 6C & 74 & 21 & + 00 + \\\hline + \end{tabular}\\[-4.2ex] + \kern1.7em% + $\underbrace{\rule{9.8em}{0pt}}_{\mbox{\lstinline{a}}}$\kern1pt% + $\underbrace{\rule{9.1em}{0pt}}_{\mbox{Füll-Bytes}}$\kern1pt% + $\underbrace{\rule{18.8em}{0pt}}_{\mbox{\lstinline{b}}}$\kern1pt% + $\underbrace{\rule{2.2em}{0pt}}_{\mbox{\lstinline{c}}}$% + \end{center} + Da danach die Ausgabe aufhört, muß an der nächsten Stelle + ein Null-Symbol stehen, das das Ende des Strings anzeigt. + Der Inhalt der darauf folgenden Speicherzelle bleibt unbekannt. + \end{enumerate} + + \exercise{Personen-Datenbank} + + Wir betrachten das folgende Programm (\gitfile{hp}{2020ws/20210128}{aufgabe-2.c}): + \begin{lstlisting} + #include <stdio.h> + #include <string.h> + + typedef struct + { + char first_name[10]; + char family_name[20]; + char day, month; + int year; + } person; + + int main (void) + { + person sls; + sls.day = 26; + sls.month = 7; + sls.year = 1951; + strcpy (sls.first_name, "Sabine"); + strcpy (sls.family_name, "Leutheusser-Schnarrenberger"); + printf ("%s %s wurde am %d.%d.%d geboren.\n", + sls.first_name, sls.family_name, sls.day, sls.month, sls.year); + return 0; + } + \end{lstlisting} + + Die Standard-Funktion \lstinline{strcpy()} bewirkt ein Kopieren eines Strings + von rechts nach links, hier also z.\,B.\ die Zuweisung der String-Konstanten + \lstinline{"Sabine"} an die String-Variable \lstinline{sls.first_name[]}. + + Das Programm wird für einen 32-Bit-Rechner compiliert und ausgeführt.\\ + (Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m32} sorgt dafür, + daß \lstinline[style=cmd]{gcc} Code für einen 32-Bit-Prozessor erzeugt.) + + \begin{lstlisting}[style=terminal] + $ ¡gcc -Wall -O -m32 aufgabe-2.c -o aufgabe-2¿ + $ ¡./aufgabe-2¿ + Sabine Leutheusser-Schnarrenberger wurde am 110.98.1701278309 geboren. + Speicherzugriffsfehler + \end{lstlisting} + + \begin{enumerate}[\quad(a)] + \item + Erklären Sie die Ausgabe des Programms einschließlich der Zahlenwerte. + \points{4} + \item + Welche Endianness hat der verwendete Rechner? + Begründen Sie Ihre Antwort. + \points{1} + \item + Wie sähe die Ausgabe auf einem Rechner mit entgegengesetzter Endianness aus? + \points{2} + \item + Erklären Sie den Speicherzugriffsfehler. + (Es kann sein, daß sich der Fehler auf Ihrem Rechner nicht bemerkbar macht. + Er ist aber trotzdem vorhanden.) + \points{2} + \end{enumerate} + + \goodbreak + + \solution + + \begin{enumerate}[\quad(a)] + \item + \textbf{Erklären Sie die Ausgabe des Programms einschließlich der Zahlenwerte.} + + Der String \lstinline{"Leutheusser-Schnarrenberger"} + hat 27 Zeichen und daher mehr als die in der Variablen + \lstinline{sls.family_name} vorgesehenen 20 Zeichen. + Das \lstinline{"nberger"} paßt nicht mehr in die String-Variable. + + Die Zuweisung \lstinline{strcpy (sls.family_name, "Leutheusser-Schnarrenberger")} + überschreibt daher 8 Speicherzellen außerhalb der String-Variablen + \lstinline{sls.family_name} mit dem String \lstinline{"nberger"} + (7 Buchstaben zzgl.\ String-Ende-Symbol) -- und damit insbesondere die Variablen + \lstinline{sls.day}, \lstinline{sls.month} und \lstinline{sls.year}. + + Die überschriebenen Speicherzellen sehen demnach folgendermaßen aus: + \begin{center} + \begin{picture}(8,1.5)(0,-0.5) + \put(0,0){\line(1,0){8}} + \put(0,1){\line(1,0){8}} + \multiput(0,0)(1,0){9}{\line(0,1){1}} + \put(0.4,0.38){\lstinline{n}} + \put(1.4,0.38){\lstinline{b}} + \put(2.4,0.38){\lstinline{e}} + \put(3.4,0.38){\lstinline{r}} + \put(4.4,0.38){\lstinline{g}} + \put(5.4,0.38){\lstinline{e}} + \put(6.4,0.38){\lstinline{r}} + \put(7.5,0.5){\makebox(0,0){\lstinline{0x00}}} + \put(0.5,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{0.95cm}{0pt}}_{\mbox{\lstinline{day}}}$}} + \put(1.5,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{0.95cm}{0pt}}_{\mbox{\lstinline{month}}}$}} + \put(4.0,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{3.95cm}{0pt}}_{\mbox{\lstinline{year}}}$}} + \put(7.0,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{1.95cm}{0pt}}_{\mbox{?}}$}} + \end{picture} + \end{center} + ("`?"' steht für zwei Speicherzellen, von denen wir nicht wissen, + wofür sie genutzt werden.) + + Wenn wir die ASCII-Zeichen in Hexadezimalzahlen umrechnen, entspricht dies: + \begin{center} + \begin{picture}(7,1.5)(0,-0.5) + \put(0,0){\line(1,0){8}} + \put(0,1){\line(1,0){8}} + \multiput(0,0)(1,0){9}{\line(0,1){1}} + \put(0.5,0.5){\makebox(0,0){\lstinline{0x6e}}} + \put(1.5,0.5){\makebox(0,0){\lstinline{0x62}}} + \put(2.5,0.5){\makebox(0,0){\lstinline{0x65}}} + \put(3.5,0.5){\makebox(0,0){\lstinline{0x72}}} + \put(4.5,0.5){\makebox(0,0){\lstinline{0x67}}} + \put(5.5,0.5){\makebox(0,0){\lstinline{0x65}}} + \put(6.5,0.5){\makebox(0,0){\lstinline{0x72}}} + \put(7.5,0.5){\makebox(0,0){\lstinline{0x00}}} + \put(0.5,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{0.95cm}{0pt}}_{\mbox{\lstinline{day}}}$}} + \put(1.5,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{0.95cm}{0pt}}_{\mbox{\lstinline{month}}}$}} + \put(4.0,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{3.95cm}{0pt}}_{\mbox{\lstinline{year}}}$}} + \put(7.0,-0.1){\makebox(0,0)[t]{$\underbrace{\rule{1.95cm}{0pt}}_{\mbox{?}}$}} + \end{picture} + \end{center} + Dies entspricht bereits genau den Werten \lstinline{110} und \lstinline{98} + für die Variablen \lstinline{sls.day} bzw.\ \lstinline{sls.month}. + + Für die Variable \lstinline{sls.year} müssen wir ihre vier Speicherzellen + unter der Berücksichtigung der Endianness des Rechners zusammenziehen. + Für Big-Endian ergibt dies \lstinline{0x65726765 == 1701996389}. + Für Little-Endian ergibt sich der Wert \lstinline{0x65677265 == 1701278309}, + der auch in der Ausgabe des Programms auftaucht. + + \item + \textbf{Welche Endianness hat der verwendete Rechner? + Begründen Sie Ihre Antwort.} + + Wie in (a) begründet, ergibt sich die Ausgabe von + \lstinline[style=terminal]{1701278309} für das Jahr + aus dem Speicherformat Little-Endian. + + \item + \textbf{Wie sähe die Ausgabe auf einem Rechner mit entgegengesetzter Endianness aus?} + + Wie in (a) begründet, ergäbe sich aus dem Speicherformat Big-Endian + die Ausgabe von \lstinline[style=terminal]{1701996389} für das Jahr. + + \item + \textbf{Erklären Sie den Speicherzugriffsfehler. + (Es kann sein, daß sich der Fehler auf Ihrem Rechner nicht bemerkbar macht. + Er ist aber trotzdem vorhanden.)} + + Die zwei in (a) mit "`?"' bezeichneten Speicherzellen + wurden ebenfalls überschrieben. + Dies ist in der Ausgabe zunächst nicht sichtbar, + bewirkt aber später den Speicherzugriffsfehler. + + (Tatsächlich handelt es sich bei den überschriebenen Speicherzellen + um einen Teil der Rücksprungadresse, die \lstinline{main()} verwendet, + um mit \lstinline{return 0} an das Betriebssystem zurückzugeben.) + + \end{enumerate} + + \textbf{Hinweis 1:} + Um auf einen solchen Lösungsweg zu kommen, wird empfohlen, + "`geheimnisvolle"' Zahlen nach hexadezimal umzurechnen + und in Speicherzellen (Zweiergruppen von Hex-Ziffern) zu zerlegen. + Oft erkennt man dann direkt ASCII-Zeichen: + Großbuchstaben beginnen mit der Hex-Ziffer \lstinline{4} oder \lstinline{5}, + Kleinbuchstaben mit \lstinline{6} oder \lstinline{7}. + + \textbf{Hinweis 2:} + Um derartige Programmierfehler in der Praxis von vorneherein zu vermeiden, + wird empfohlen, anstelle von \lstinline{strcpy()} + grundsätzlich die Funktion \lstinline{strncpy()} zu verwenden. + Diese erwartet einen zusätzlichen Parameter, + der die maximal zulässige Länge des Strings enthält. + Ohne einen derartigen expliziten Parameter kann die Funktion nicht wissen, + wie lang die Variable ist, in der der String gespeichert werden soll. + + \exercise{Objektorientierte Tier-Datenbank} + + Das unten dargestellte Programm (Datei: \gitfile{hp}{2020ws/20210128}{aufgabe-3a.c}) + soll Daten von Tieren verwalten. + + Beim Compilieren erscheinen die folgende Fehlermeldungen: + \begin{lstlisting}[style=terminal] + $ ¡gcc -std=c99 -Wall -O aufgabe-2a.c -o aufgabe-2a¿ + aufgabe-2a.c: In function 'main': + aufgabe-2a.c:31: error: 'animal' has no member named 'wings' + aufgabe-2a.c:37: error: 'animal' has no member named 'legs' + \end{lstlisting} + + Der Programmierer nimmt die auf der nächsten Seite in Rot dargestellten Ersetzungen vor\\ + (Datei: \gitfile{hp}{2020ws/20210128}{aufgabe-3b.c}). + Daraufhin gelingt das Compilieren, und die Ausgabe des Programms lautet: + \begin{lstlisting}[style=terminal] + $ ¡gcc -std=c99 -Wall -O aufgabe-2b.c -o aufgabe-2b¿ + $ ¡./aufgabe-2b¿ + A duck has 2 legs. + Error in animal: cow + \end{lstlisting} + + \begin{itemize} + \item[(a)] + Erklären Sie die o.\,a.\ Compiler-Fehlermeldungen. + \points{2} + \item[(b)] + Wieso verschwinden die Fehlermeldungen nach den o.\,a.\ Ersetzungen? + \points{3} + \item[(c)] + Erklären Sie die Ausgabe des Programms. + \points{5} + \item[(d)] + Beschreiben Sie -- in Worten und/oder als C-Quelltext -- einen Weg, + das Programm so zu berichtigen, daß es die Eingabedaten + (``A duck has 2 wings. A cow has 4 legs.'') korrekt speichert und ausgibt.\\ + \points{4} +% \item[(e)] +% Schreiben Sie das Programm so um, +% daß es keine expliziten Typumwandlungen mehr benötigt.\par +% Hinweis: Verwenden Sie \lstinline{union}. +% \points{4} +% \item[(f)] +% Schreiben Sie das Programm weiter um, +% so daß es die Objektinstanzen \lstinline{duck} und \lstinline{cow} +% dynamisch erzeugt.\par +% Hinweis: Verwenden Sie \lstinline{malloc()} und schreiben Sie Konstruktoren. +% \points{4} +% \item[(g)] +% Schreiben Sie das Programm weiter um, +% so daß die Ausgabe nicht mehr direkt im Hauptprogramm erfolgt, +% sondern stattdessen eine virtuelle Methode \lstinline{print()} +% aufgerufen wird.\par +% Hinweis: Verwenden Sie in den Objekten Zeiger auf Funktionen, +% und initialisieren Sie diese in den Konstruktoren. +% \points{4} + \end{itemize} + + \begin{minipage}[t]{0.34\textwidth} + \begin{lstlisting}[gobble=6,xleftmargin=0pt] + #include <stdio.h> + + #define ANIMAL 0 + #define WITH_WINGS 1 + #define WITH_LEGS 2 + + typedef struct animal + { + int type; + char *name; + } animal; + + typedef struct with_wings + { + int wings; + } with_wings; + + typedef struct with_legs + { + int legs; + } with_legs; + \end{lstlisting} + \end{minipage}\hfill + \begin{minipage}[t]{0.65\textwidth} + \begin{lstlisting}[gobble=6,xleftmargin=0pt] + int main (void) + { + animal *a[2]; + + animal duck; + a[0] = &duck; + a[0]->type = WITH_WINGS; + a[0]->name = "duck"; + a[0]->wings = 2; + + animal cow; + a[1] = &cow; + a[1]->type = WITH_LEGS; + a[1]->name = "cow"; + a[1]->legs = 4; + + for (int i = 0; i < 2; i++) + if (a[i]->type == WITH_LEGS) + printf ("A %s has %d legs.\n", a[i]->name, + ((with_legs *) a[i])-> legs); + else if (a[i]->type == WITH_WINGS) + printf ("A %s has %d wings.\n", a[i]->name, + ((with_wings *) a[i])-> wings); + else + printf ("Error in animal: %s\n", a[i]->name); + + return 0; + } + \end{lstlisting} + \begin{picture}(0,0) + \color{red} + \put(3.7,6.207){\vector(-1,0){0.7}} + \put(3.8,6.207){\makebox(0,0)[l]{\lstinline[basicstyle=\color{red}]{((with_legs *) a[1])->legs = 4;}}} + \put(4.0,8.735){\vector(-1,0){0.7}} + \put(4.1,8.735){\makebox(0,0)[l]{\lstinline[basicstyle=\color{red}]{((with_wings *) a[0])->wings = 2;}}} + \end{picture} + \end{minipage} + + \solution + + \begin{itemize} + \item[(a)] + \textbf{Erklären Sie die o.\,a.\ Compiler-Fehlermeldungen.} + + \lstinline{a[0]} und \lstinline{a[1]} + sind gemäß der Deklaration \lstinline{animal *a[2]} + Zeiger auf Variablen vom Typ \lstinline{animal} (ein \lstinline{struct}). + Wenn man diesen Zeiger dereferenziert (\lstinline{->}), + erhält man eine \lstinline{animal}-Variable. + Diese enthält keine Datenfelder \lstinline{wings} bzw.\ \lstinline{legs}. + + \item[(b)] + \textbf{Wieso verschwinden die Fehlermeldungen nach den o.\,a.\ Ersetzungen?} + + Durch die \emph{explizite Typumwandlung des Zeigers\/} + erhalten wir einen Zeiger auf eine \lstinline{with_wings}- + bzw.\ auf eine \lstinline{with_legs}-Variable. + Diese enthalten die Datenfelder \lstinline{wings} bzw.\ \lstinline{legs}. + + \item[(c)] + \textbf{Erklären Sie die Ausgabe des Programms.} + + Durch die explizite Typumwandlung des Zeigers + zeigt \lstinline{a[0]} auf eine \lstinline{with_wings}-Variable. + Diese enthält nur ein einziges Datenfeld \lstinline{wings}, + das an genau derselben Stelle im Speicher liegt + wie \lstinline{a[0]->type}, also das Datenfeld \lstinline{type} + der \lstinline{animal}-Variable, auf die der Zeiger \lstinline{a[0]} zeigt. + Durch die Zuweisung der Zahl \lstinline{2} + an \lstinline{((with_wings *) a[0])->wings} + überschreiben wir also \lstinline{a[0]->type}, + so daß das \lstinline{if} in der \lstinline{for}-Schleife + \lstinline{a[0]} als \lstinline{WITH_LEGS} erkennt. + + Bei der Ausgabe \lstinline[style=terminal]{A duck has 2 legs.} + wird das Datenfeld \lstinline{((with_legs *)a[0])->legs} als Zahl ausgegeben. + Dieses Datenfeld befindet sich in denselben Speicherzellen wie + \lstinline{a[0]->type} und \lstinline{((with_wings *)} % :-( + \lstinline{a[0]->wings} + und hat daher ebenfalls den Wert 2. + + Auf die gleiche Weise überschreiben wir durch die Zuweisung der Zahl 4 + an \lstinline{((with_legs *) a[1])->legs} + das Datenfeld \lstinline{a[0]->type}, + so daß das \lstinline{if} in der \lstinline{for}-Schleife + \lstinline{a[1]} als unbekanntes Tier (Nr.\ 4) erkennt und + \lstinline[style=terminal]{Error in animal: cow} ausgibt. + + \item[(d)] + \textbf{Beschreiben Sie -- in Worten und/oder als C-Quelltext -- einen Weg, + das Programm so zu berichtigen, daß es die Eingabedaten + (``A duck has 2 wings. A cow has 4 legs.'') korrekt speichert und ausgibt.} + + Damit die \emph{Vererbung\/} zwischen den Objekten + \lstinline{animal}, \lstinline{with_wings} und \lstinline{with_legs} + funktioniert, müssen die abgeleiteten Klassen \lstinline{with_wings} und \lstinline{with_legs} + alle Datenfelder der Basisklasse \lstinline{animal} erben. + In C geschieht dies explizit; die Datenfelder müssen in den + abgeleiteten Klassen neu angegeben werden + (siehe \gitfile{hp}{2020ws/20210128}{loesung-3d-1.c}): + + \begin{lstlisting}[gobble=8] + typedef struct animal + { + int type; + char *name; + } animal; + + typedef struct with_wings + { + int type; + char *name; + int wings; + } with_wings; + + typedef struct with_legs + { + int type; + char *name; + int legs; + } with_legs; + \end{lstlisting} + + Zusätzlich ist es notwendig, + die Instanzen \lstinline{duck} und \lstinline{cow} + der abgeleiteten Klassen \lstinline{with_wings} und \lstinline{with_legs} + auch als solche zu deklarieren, + damit für sie genügend Speicher reserviert wird: + + \begin{lstlisting}[gobble=8] + animal *a[2]; + + with_wings duck; + a[0] = (animal *) &duck; + a[0]->type = WITH_WINGS; + a[0]->name = "duck"; + ((with_wings *) a[0])->wings = 2; + + with_legs cow; + a[1] = (animal *) &cow; + a[1]->type = WITH_LEGS; + a[1]->name = "cow"; + ((with_legs *) a[1])->legs = 4; + \end{lstlisting} + + Wenn man dies vergißt und sie nur als \lstinline{animal} deklariert, + wird auch nur Speicherplatz für (kleinere) + \lstinline{animal}-Variable angelegt. + Dadurch kommt es zu Speicherzugriffen außerhalb der + deklarierten Variablen, was letztlich zu einem Absturz führt + (siehe \gitfile{hp}{2020ws/20210128}{loesung-3d-0f.c}). + + Für die Zuweisung eines Zeigers auf \lstinline{duck} + an \lstinline{a[0]}, also an einen Zeiger auf \lstinline{animal} + wird eine weitere explizite Typumwandlung notwendig. + Entsprechendes gilt für die Zuweisung eines Zeigers auf \lstinline{cow} + an \lstinline{a[1]}. + + Es ist sinnvoll, explizite Typumwandlungen so weit wie möglich zu vermeiden. + Es ist einfacher und gleichzeitig sicherer, + direkt in die Variablen \lstinline{duck} und \lstinline{cow} + zu schreiben, anstatt dies über die Zeiger \lstinline{a[0]} + und \lstinline{a[1]} zu tun + (siehe \gitfile{hp}{2020ws/20210128}{loesung-3d-2.c}): + + \begin{lstlisting}[gobble=8] + animal *a[2]; + + with_wings duck; + a[0] = (animal *) &duck; + duck.type = WITH_WINGS; + duck.name = "duck"; + duck.wings = 2; + + with_legs cow; + a[1] = (animal *) &cow; + cow.type = WITH_LEGS; + cow.name = "cow"; + cow.legs = 4; + \end{lstlisting} + + \item[(e)] + \textbf{Schreiben Sie das Programm so um, + daß es keine expliziten Typumwandlungen mehr benötigt.}\par + \textbf{Hinweis: Verwenden Sie \lstinline{union}.} + + Siehe \gitfile{hp}{2020ws/20210128}{loesung-3e.c}. + + Diese Lösung basiert auf \gitfile{hp}{2020ws/20210128}{loesung-3d-2.c}, + da diese bereits weniger explizite Typumwandlungen enthält + als \gitfile{hp}{2020ws/20210128}{loesung-3d-1.c}. + + Arbeitsschritte: + \begin{itemize} + \item + Umbenennen des Basistyps \lstinline{animal} in \lstinline{base}, + damit wir den Bezeichner \lstinline{animal} + für die \lstinline{union} verwenden können + \item + Schreiben einer \lstinline{union animal}, + die die drei Klassen \lstinline{base}, + \lstinline{with_wings} und \lstinline{with_legs} + als Datenfelder enthält + \item + Umschreiben der Initialisierungen: + Zugriff auf Datenfelder erfolgt nun durch + z.\,B.\ \lstinline{a[0]->b.name}. + Hierbei ist \lstinline{b} der Name des \lstinline{base}-Datenfelds + innerhalb der \lstinline{union animal}. + \item + Auf gleiche Weise schreiben wir die \lstinline{if}-Bedingungen + innerhalb der \lstinline{for}-Schleife + sowie die Parameter der \lstinline{printf()}-Aufrufe um. + \end{itemize} + Explizite Typumwandlungen sind nun nicht mehr nötig. + + Nachteil dieser Lösung: + Jede Objekt-Variable belegt nun Speicherplatz + für die gesamte \lstinline{union animal}, + anstatt nur für die benötigte Variable vom Typ + \lstinline{with_wings} oder \lstinline{with_legs}. + Dies kann zu einer Verschwendung von Speicherplatz führen, + auch wenn dies in diesem Beispielprogramm tatsächlich nicht der Fall ist. + + \item[(f)] + \textbf{Schreiben Sie das Programm weiter um, + so daß es die Objektinstanzen \lstinline{duck} und \lstinline{cow} + dynamisch erzeugt.}\par + \textbf{Hinweis: Verwenden Sie \lstinline{malloc()} und schreiben Sie Konstruktoren.} + + Siehe \gitfile{hp}{2020ws/20210128}{loesung-3f.c}. + + \item[(g)] + \textbf{Schreiben Sie das Programm weiter um, + so daß die Ausgabe nicht mehr direkt im Hauptprogramm erfolgt, + sondern stattdessen eine virtuelle Methode \lstinline{print()} + aufgerufen wird.}\par + \textbf{Hinweis: Verwenden Sie in den Objekten Zeiger auf Funktionen, + und initialisieren Sie diese in den Konstruktoren.} + + Siehe \gitfile{hp}{2020ws/20210128}{loesung-3g.c}. + + \end{itemize} + +\end{document} diff --git a/20210128/hp-uebung-20210128.pdf b/20210128/hp-uebung-20210128.pdf new file mode 100644 index 0000000000000000000000000000000000000000..350451858390509e6e1c0b4e13eee0ebf42d2f8f Binary files /dev/null and b/20210128/hp-uebung-20210128.pdf differ diff --git a/20210128/hp-uebung-20210128.tex b/20210128/hp-uebung-20210128.tex new file mode 100644 index 0000000000000000000000000000000000000000..49b831bc5b00720a0e3ff714da0aff587878253b --- /dev/null +++ b/20210128/hp-uebung-20210128.tex @@ -0,0 +1,305 @@ +% hp-uebung-20210128.pdf - Exercises on Low-Level Programming +% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Peter Gerwinski +% +% This document is free software: you can redistribute it and/or +% modify it either under the terms of the Creative Commons +% Attribution-ShareAlike 3.0 License, or under the terms of the +% GNU General Public License as published by the Free Software +% Foundation, either version 3 of the License, or (at your option) +% any later version. +% +% This document is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this document. If not, see <http://www.gnu.org/licenses/>. +% +% You should have received a copy of the Creative Commons +% Attribution-ShareAlike 3.0 Unported License along with this +% document. If not, see <http://creativecommons.org/licenses/>. + +% README: Speicherformate von Zahlen, Personen-Datenbank, objektorientierte Tier-Datenbank + +\documentclass[a4paper]{article} + +\usepackage{pgscript} + +\begin{document} + +% \thispagestyle{empty} + + \section*{Hardwarenahe Programmierung\\ + Übungsaufgaben -- 28.\ Januar 2021} + + Diese Übung enthält Punkteangaben wie in einer Klausur. + Um zu "`bestehen"', müssen Sie innerhalb von 100 Minuten + unter Verwendung ausschließlich zugelassener Hilfsmittel + 17 Punkte (von insgesamt \totalpoints) erreichen. + + \exercise{Speicherformate von Zahlen} + + Wir betrachten das folgende Programm (\gitfile{hp}{2020ws/20210128}{aufgabe-1.c}): + \begin{lstlisting} + #include <stdio.h> + #include <stdint.h> + + typedef struct + { + uint32_t a; + uint64_t b; + uint8_t c; + } three_numbers; + + int main (void) + { + three_numbers xyz = { 1819042120, 2410670883059281007, 0 }; + printf ("%s\n", &xyz); + return 0; + } + \end{lstlisting} + + Das Programm wird für einen 32-Bit-Rechner compiliert und ausgeführt.\\ + (Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m32} sorgt dafür, + daß \lstinline[style=cmd]{gcc} Code für einen 32-Bit-Prozessor erzeugt.) + + \begin{lstlisting}[style=terminal] + $ ¡gcc -Wall -m32 aufgabe-2.c -o aufgabe-2¿ + aufgabe-2.c: In function "main": + aufgabe-2.c:14:13: warning: format "%s" expects argument of type "char *", but + argument 2 has type "three_numbers * {aka struct <anonymous> *}" [-Wformat=] + printf ("%s\n", &xyz); + ^ + $ ¡./aufgabe-2¿ + Hallo, Welt! + \end{lstlisting} + + \begin{enumerate}[\quad(a)] + \item + Erklären Sie die beim Compilieren auftretende Warnung. + \points{2} + \item + Erklären Sie die Ausgabe des Programms. + \points{4} + \item + Welche Endianness hat der verwendete Rechner? + Wie sähe die Ausgabe auf einem Rechner mit entgegengesetzter Endianness aus? + \points{2} + \item + Dasselbe Programm wird nun für einen 64-Bit-Rechner compiliert und ausgeführt.\\ + (Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m64} sorgt dafür, + daß \lstinline[style=cmd]{gcc} Code für einen 64-Bit-Prozessor erzeugt.) + \begin{lstlisting}[style=terminal,gobble=8] + $ ¡gcc -Wall -m64 aufgabe-2.c -o aufgabe-2¿ + aufgabe-2.c: In function "main": + aufgabe-2.c:14:13: warning: format "%s" expects argument of type "char *", + but argument 2 has type "three_numbers * {aka struct <anonymous> *}" + [-Wformat=] + printf ("%s\n", &xyz); + ^ + $ ¡./aufgabe-2¿ + Hall5V + \end{lstlisting} + (Es ist möglich, daß die konkrete Ausgabe auf Ihrem Rechner anders aussieht.)\par + Erklären Sie die geänderte Ausgabe des Programms. + \points{3} + \end{enumerate} + + \clearpage + \exercise{Personen-Datenbank} + + Wir betrachten das folgende Programm (\gitfile{hp}{2020ws/20210128}{aufgabe-2.c}): + \begin{lstlisting} + #include <stdio.h> + #include <string.h> + + typedef struct + { + char first_name[10]; + char family_name[20]; + char day, month; + int year; + } person; + + int main (void) + { + person sls; + sls.day = 26; + sls.month = 7; + sls.year = 1951; + strcpy (sls.first_name, "Sabine"); + strcpy (sls.family_name, "Leutheusser-Schnarrenberger"); + printf ("%s %s wurde am %d.%d.%d geboren.\n", + sls.first_name, sls.family_name, sls.day, sls.month, sls.year); + return 0; + } + \end{lstlisting} + + Die Standard-Funktion \lstinline{strcpy()} bewirkt ein Kopieren eines Strings + von rechts nach links, hier also z.\,B.\ die Zuweisung der String-Konstanten + \lstinline{"Sabine"} an die String-Variable \lstinline{sls.first_name[]}. + + Das Programm wird für einen 32-Bit-Rechner compiliert und ausgeführt.\\ + (Die \lstinline[style=cmd]{gcc}-Option \lstinline[style=cmd]{-m32} sorgt dafür, + daß \lstinline[style=cmd]{gcc} Code für einen 32-Bit-Prozessor erzeugt.) + + \begin{lstlisting}[style=terminal] + $ ¡gcc -Wall -O -m32 aufgabe-2.c -o aufgabe-2¿ + $ ¡./aufgabe-2¿ + Sabine Leutheusser-Schnarrenberger wurde am 110.98.1701278309 geboren. + Speicherzugriffsfehler + \end{lstlisting} + + \begin{enumerate}[\quad(a)] + \item + Erklären Sie die Ausgabe des Programms einschließlich der Zahlenwerte. + \points{4} + \item + Welche Endianness hat der verwendete Rechner? + Begründen Sie Ihre Antwort. + \points{1} + \item + Wie sähe die Ausgabe auf einem Rechner mit entgegengesetzter Endianness aus? + \points{2} + \item + Erklären Sie den Speicherzugriffsfehler. + (Es kann sein, daß sich der Fehler auf Ihrem Rechner nicht bemerkbar macht. + Er ist aber trotzdem vorhanden.) + \points{2} + \end{enumerate} + + \clearpage + \exercise{Objektorientierte Tier-Datenbank} + + Das unten dargestellte Programm (Datei: \gitfile{hp}{2020ws/20210128}{aufgabe-3a.c}) + soll Daten von Tieren verwalten. + + Beim Compilieren erscheinen die folgende Fehlermeldungen: + \begin{lstlisting}[style=terminal] + $ ¡gcc -std=c99 -Wall -O aufgabe-2a.c -o aufgabe-2a¿ + aufgabe-2a.c: In function 'main': + aufgabe-2a.c:31: error: 'animal' has no member named 'wings' + aufgabe-2a.c:37: error: 'animal' has no member named 'legs' + \end{lstlisting} + + Der Programmierer nimmt die auf der nächsten Seite in Rot dargestellten Ersetzungen vor\\ + (Datei: \gitfile{hp}{2020ws/20210128}{aufgabe-3b.c}). + Daraufhin gelingt das Compilieren, und die Ausgabe des Programms lautet: + \begin{lstlisting}[style=terminal] + $ ¡gcc -std=c99 -Wall -O aufgabe-2b.c -o aufgabe-2b¿ + $ ¡./aufgabe-2b¿ + A duck has 2 legs. + Error in animal: cow + \end{lstlisting} + + \begin{itemize} + \item[(a)] + Erklären Sie die o.\,a.\ Compiler-Fehlermeldungen. + \points{2} + \item[(b)] + Wieso verschwinden die Fehlermeldungen nach den o.\,a.\ Ersetzungen? + \points{3} + \item[(c)] + Erklären Sie die Ausgabe des Programms. + \points{5} + \item[(d)] + Beschreiben Sie -- in Worten und/oder als C-Quelltext -- einen Weg, + das Programm so zu berichtigen, daß es die Eingabedaten + (``A duck has 2 wings. A cow has 4 legs.'') korrekt speichert und ausgibt.\\ + \points{4} +% \item[(e)] +% Schreiben Sie das Programm so um, +% daß es keine expliziten Typumwandlungen mehr benötigt.\par +% Hinweis: Verwenden Sie \lstinline{union}. +% \points{4} +% \item[(f)] +% Schreiben Sie das Programm weiter um, +% so daß es die Objektinstanzen \lstinline{duck} und \lstinline{cow} +% dynamisch erzeugt.\par +% Hinweis: Verwenden Sie \lstinline{malloc()} und schreiben Sie Konstruktoren. +% \points{4} +% \item[(g)] +% Schreiben Sie das Programm weiter um, +% so daß die Ausgabe nicht mehr direkt im Hauptprogramm erfolgt, +% sondern stattdessen eine virtuelle Methode \lstinline{print()} +% aufgerufen wird.\par +% Hinweis: Verwenden Sie in den Objekten Zeiger auf Funktionen, +% und initialisieren Sie diese in den Konstruktoren. +% \points{4} + \end{itemize} + + \begin{minipage}[t]{0.34\textwidth} + \begin{lstlisting}[gobble=6,xleftmargin=0pt] + #include <stdio.h> + + #define ANIMAL 0 + #define WITH_WINGS 1 + #define WITH_LEGS 2 + + typedef struct animal + { + int type; + char *name; + } animal; + + typedef struct with_wings + { + int wings; + } with_wings; + + typedef struct with_legs + { + int legs; + } with_legs; + \end{lstlisting} + \end{minipage}\hfill + \begin{minipage}[t]{0.65\textwidth} + \begin{lstlisting}[gobble=6,xleftmargin=0pt] + int main (void) + { + animal *a[2]; + + animal duck; + a[0] = &duck; + a[0]->type = WITH_WINGS; + a[0]->name = "duck"; + a[0]->wings = 2; + + animal cow; + a[1] = &cow; + a[1]->type = WITH_LEGS; + a[1]->name = "cow"; + a[1]->legs = 4; + + for (int i = 0; i < 2; i++) + if (a[i]->type == WITH_LEGS) + printf ("A %s has %d legs.\n", a[i]->name, + ((with_legs *) a[i])-> legs); + else if (a[i]->type == WITH_WINGS) + printf ("A %s has %d wings.\n", a[i]->name, + ((with_wings *) a[i])-> wings); + else + printf ("Error in animal: %s\n", a[i]->name); + + return 0; + } + \end{lstlisting} + \begin{picture}(0,0) + \color{red} + \put(3.7,6.207){\vector(-1,0){0.7}} + \put(3.8,6.207){\makebox(0,0)[l]{\lstinline[basicstyle=\color{red}]{((with_legs *) a[1])->legs = 4;}}} + \put(4.0,8.735){\vector(-1,0){0.7}} + \put(4.1,8.735){\makebox(0,0)[l]{\lstinline[basicstyle=\color{red}]{((with_wings *) a[0])->wings = 2;}}} + \end{picture} + \end{minipage} + + \begin{flushright} + \textit{Viel Erfolg!} + \end{flushright} + + \makeatletter + \immediate\write\@mainaux{\string\gdef\string\totalpoints{\arabic{points}}} + \makeatother + +\end{document} diff --git a/20210128/loesung-1-1.c b/20210128/loesung-1-1.c new file mode 100644 index 0000000000000000000000000000000000000000..175923f7250d0747a21df5f33f8a3761393d1d7f --- /dev/null +++ b/20210128/loesung-1-1.c @@ -0,0 +1,18 @@ +#include <stdio.h> +#include <stdint.h> + +typedef struct +{ + uint32_t a; + uint64_t b; + uint8_t c; +} three_numbers; + +int main (void) +{ + three_numbers xyz = { 1819042120, 2410670883059281007, 0 }; + printf ("%x %x %x\n", xyz.a, xyz.b, xyz.c); + printf ("%08x %016x %02x\n", xyz.a, xyz.b, xyz.c); + printf ("%s\n", &xyz); + return 0; +} diff --git a/20210128/loesung-1-2.c b/20210128/loesung-1-2.c new file mode 100644 index 0000000000000000000000000000000000000000..07ca06832cc58c1b8243f9afd05aec57bb12b1c4 --- /dev/null +++ b/20210128/loesung-1-2.c @@ -0,0 +1,18 @@ +#include <stdio.h> +#include <stdint.h> + +typedef struct +{ + uint32_t a; + uint64_t b; + uint8_t c; +} three_numbers; + +int main (void) +{ + three_numbers xyz = { 1819042120, 2410670883059281007, 0 }; + printf ("%x %lx %x\n", xyz.a, xyz.b, xyz.c); + printf ("%08x %016lx %02x\n", xyz.a, xyz.b, xyz.c); + printf ("%s\n", &xyz); + return 0; +} diff --git a/20210128/loesung-2-1.c b/20210128/loesung-2-1.c new file mode 100644 index 0000000000000000000000000000000000000000..416c5dfa2cba2f7dc68b72551ec6a5c8ce8bab79 --- /dev/null +++ b/20210128/loesung-2-1.c @@ -0,0 +1,23 @@ +#include <stdio.h> +#include <string.h> + +typedef struct +{ + char first_name[10]; + char family_name[20]; + char day, month; + int year; +} person; + +int main (void) +{ + person sls; + strcpy (sls.first_name, "Sabine"); + strcpy (sls.family_name, "Leutheusser-Schnarrenberger"); + sls.day = 26; + sls.month = 7; + sls.year = 1951; + printf ("%s %s wurde am %d.%d.%d geboren.\n", + sls.first_name, sls.family_name, sls.day, sls.month, sls.year); + return 0; +} diff --git a/20210128/loesung-2-2.c b/20210128/loesung-2-2.c new file mode 100644 index 0000000000000000000000000000000000000000..825373e61475ebc67e9cac6929b6e004715a7cad --- /dev/null +++ b/20210128/loesung-2-2.c @@ -0,0 +1,23 @@ +#include <stdio.h> +#include <string.h> + +typedef struct +{ + char first_name[10]; + char family_name[20]; + char day, month; + int year; +} person; + +int main (void) +{ + person sls; + sls.day = 26; + sls.month = 7; + sls.year = 1951; + strncpy (sls.first_name, "Sabine", 10); + strncpy (sls.family_name, "Leutheusser-Schnarrenberger", 20); + printf ("%s %s wurde am %d.%d.%d geboren.\n", + sls.first_name, sls.family_name, sls.day, sls.month, sls.year); + return 0; +} diff --git a/20210128/loesung-2-3.c b/20210128/loesung-2-3.c new file mode 100644 index 0000000000000000000000000000000000000000..7a4b1bfaf9e67a164ee865a0ae4ef69606255de0 --- /dev/null +++ b/20210128/loesung-2-3.c @@ -0,0 +1,23 @@ +#include <stdio.h> +#include <string.h> + +typedef struct +{ + char first_name[10]; + char family_name[20]; + char day, month; + int year; +} person; + +int main (void) +{ + person sls; + sls.day = 26; + sls.month = 7; + sls.year = 1951; + strncpy (sls.first_name, "Sabine", 9); + strncpy (sls.family_name, "Leutheusser-Schnarrenberger", 19); + printf ("%s %s wurde am %d.%d.%d geboren.\n", + sls.first_name, sls.family_name, sls.day, sls.month, sls.year); + return 0; +} diff --git a/20210128/loesung-2-4.c b/20210128/loesung-2-4.c new file mode 100644 index 0000000000000000000000000000000000000000..3c635dfa7e3923eb678469166bf218e1640927a2 --- /dev/null +++ b/20210128/loesung-2-4.c @@ -0,0 +1,25 @@ +#include <stdio.h> +#include <string.h> + +typedef struct +{ + char first_name[10]; + char family_name[20]; + char day, month; + int year; +} person; + +int main (void) +{ + person sls; + sls.day = 26; + sls.month = 7; + sls.year = 1951; + strncpy (sls.first_name, "Sabine", 9); + sls.first_name[9] = 0; + strncpy (sls.family_name, "Leutheusser-Schnarrenberger", 19); + sls.family_name[19] = 0; + printf ("%s %s wurde am %d.%d.%d geboren.\n", + sls.first_name, sls.family_name, sls.day, sls.month, sls.year); + return 0; +} diff --git a/20210128/loesung-3d-0f.c b/20210128/loesung-3d-0f.c new file mode 100644 index 0000000000000000000000000000000000000000..04b2d3e8956f4790b3f2ffdf3a314994c640513e --- /dev/null +++ b/20210128/loesung-3d-0f.c @@ -0,0 +1,54 @@ +#include <stdio.h> + +#define ANIMAL 0 +#define WITH_WINGS 1 +#define WITH_LEGS 2 + +typedef struct animal +{ + int type; + char *name; +} animal; + +typedef struct with_wings +{ + int type; + char *name; + int wings; +} with_wings; + +typedef struct with_legs +{ + int type; + char *name; + int legs; +} with_legs; + +int main (void) +{ + animal *a[2]; + + animal duck; + a[0] = &duck; + a[0]->type = WITH_WINGS; + a[0]->name = "duck"; + ((with_wings *) a[0])->wings = 2; + + animal cow; + a[1] = &cow; + a[1]->type = WITH_LEGS; + a[1]->name = "cow"; + ((with_legs *) a[1])->legs = 4; + + for (int i = 0; i < 2; i++) + if (a[i]->type == WITH_LEGS) + printf ("A %s has %d legs.\n", a[i]->name, + ((with_legs *) a[i])-> legs); + else if (a[i]->type == WITH_WINGS) + printf ("A %s has %d wings.\n", a[i]->name, + ((with_wings *) a[i])-> wings); + else + printf ("Error in animal: %s\n", a[i]->name); + + return 0; +} diff --git a/20210128/loesung-3d-1.c b/20210128/loesung-3d-1.c new file mode 100644 index 0000000000000000000000000000000000000000..349523a7d99e33ba81094ffbc8907773b5a3a251 --- /dev/null +++ b/20210128/loesung-3d-1.c @@ -0,0 +1,54 @@ +#include <stdio.h> + +#define ANIMAL 0 +#define WITH_WINGS 1 +#define WITH_LEGS 2 + +typedef struct animal +{ + int type; + char *name; +} animal; + +typedef struct with_wings +{ + int type; + char *name; + int wings; +} with_wings; + +typedef struct with_legs +{ + int type; + char *name; + int legs; +} with_legs; + +int main (void) +{ + animal *a[2]; + + with_wings duck; + a[0] = (animal *) &duck; + a[0]->type = WITH_WINGS; + a[0]->name = "duck"; + ((with_wings *) a[0])->wings = 2; + + with_legs cow; + a[1] = (animal *) &cow; + a[1]->type = WITH_LEGS; + a[1]->name = "cow"; + ((with_legs *) a[1])->legs = 4; + + for (int i = 0; i < 2; i++) + if (a[i]->type == WITH_LEGS) + printf ("A %s has %d legs.\n", a[i]->name, + ((with_legs *) a[i])-> legs); + else if (a[i]->type == WITH_WINGS) + printf ("A %s has %d wings.\n", a[i]->name, + ((with_wings *) a[i])-> wings); + else + printf ("Error in animal: %s\n", a[i]->name); + + return 0; +} diff --git a/20210128/loesung-3d-2.c b/20210128/loesung-3d-2.c new file mode 100644 index 0000000000000000000000000000000000000000..f831a75eda1f3e784c8e6c1f24a83d9d6b55ee6c --- /dev/null +++ b/20210128/loesung-3d-2.c @@ -0,0 +1,54 @@ +#include <stdio.h> + +#define ANIMAL 0 +#define WITH_WINGS 1 +#define WITH_LEGS 2 + +typedef struct animal +{ + int type; + char *name; +} animal; + +typedef struct with_wings +{ + int type; + char *name; + int wings; +} with_wings; + +typedef struct with_legs +{ + int type; + char *name; + int legs; +} with_legs; + +int main (void) +{ + animal *a[2]; + + with_wings duck; + a[0] = (animal *) &duck; + duck.type = WITH_WINGS; + duck.name = "duck"; + duck.wings = 2; + + with_legs cow; + a[1] = (animal *) &cow; + cow.type = WITH_LEGS; + cow.name = "cow"; + cow.legs = 4; + + for (int i = 0; i < 2; i++) + if (a[i]->type == WITH_LEGS) + printf ("A %s has %d legs.\n", a[i]->name, + ((with_legs *) a[i])-> legs); + else if (a[i]->type == WITH_WINGS) + printf ("A %s has %d wings.\n", a[i]->name, + ((with_wings *) a[i])-> wings); + else + printf ("Error in animal: %s\n", a[i]->name); + + return 0; +} diff --git a/20210128/loesung-3e.c b/20210128/loesung-3e.c new file mode 100644 index 0000000000000000000000000000000000000000..b984d9253b9c379a88f0fc0ca130c88c3103f8f3 --- /dev/null +++ b/20210128/loesung-3e.c @@ -0,0 +1,61 @@ +#include <stdio.h> + +#define ANIMAL 0 +#define WITH_WINGS 1 +#define WITH_LEGS 2 + +typedef struct +{ + int type; + char *name; +} base; + +typedef struct +{ + int type; + char *name; + int wings; +} with_wings; + +typedef struct +{ + int type; + char *name; + int legs; +} with_legs; + +typedef union +{ + base b; + with_wings w; + with_legs l; +} animal; + +int main (void) +{ + animal *a[2]; + + animal duck; + a[0] = &duck; + duck.b.type = WITH_WINGS; + duck.b.name = "duck"; + duck.w.wings = 2; + + animal cow; + a[1] = &cow; + cow.b.type = WITH_LEGS; + cow.b.name = "cow"; + cow.l.legs = 4; + + for (int i = 0; i < 2; i++) + if (a[i]->b.type == WITH_LEGS) + printf ("A %s has %d legs.\n", a[i]->b.name, + a[i]->l.legs); + else if (a[i]->b.type == WITH_WINGS) + printf ("A %s has %d wings.\n", a[i]->b.name, + a[i]->w.wings); + else + printf ("Error in animal: %s\n", a[i]->b.name); + + return 0; +} diff --git a/20210128/loesung-3f.c b/20210128/loesung-3f.c new file mode 100644 index 0000000000000000000000000000000000000000..7b949e6365fc3839e6adc7661e0f8b4dd0c059df --- /dev/null +++ b/20210128/loesung-3f.c @@ -0,0 +1,69 @@ +#include <stdio.h> +#include <stdlib.h> + +#define ANIMAL 0 +#define WITH_WINGS 1 +#define WITH_LEGS 2 + +typedef struct +{ + int type; + char *name; +} base; + +typedef struct +{ + int type; + char *name; + int wings; +} with_wings; + +typedef struct +{ + int type; + char *name; + int legs; +} with_legs; + +typedef union +{ + base b; + with_wings w; + with_legs l; +} animal; + +animal *new_with_wings (char *name, int wings) +{ + animal *a = malloc (sizeof (with_wings)); + a->b.type = WITH_WINGS; + a->b.name = name; + a->w.wings = wings; + return a; +} + +animal *new_with_legs (char *name, int legs) +{ + animal *a = malloc (sizeof (with_legs)); + a->b.type = WITH_LEGS; + a->b.name = name; + a->l.legs = legs; + return a; +} + +int main (void) +{ + animal *a[2] = { new_with_wings ("duck", 2), + new_with_legs ("cow", 4) }; + + for (int i = 0; i < 2; i++) + if (a[i]->b.type == WITH_LEGS) + printf ("A %s has %d legs.\n", a[i]->b.name, + a[i]->l.legs); + else if (a[i]->b.type == WITH_WINGS) + printf ("A %s has %d wings.\n", a[i]->b.name, + a[i]->w.wings); + else + printf ("Error in animal: %s\n", a[i]->b.name); + + return 0; +} diff --git a/20210128/loesung-3g.c b/20210128/loesung-3g.c new file mode 100644 index 0000000000000000000000000000000000000000..b453a52dbe0ef27399255819808b3f6e562ba3ef --- /dev/null +++ b/20210128/loesung-3g.c @@ -0,0 +1,77 @@ +#include <stdio.h> +#include <stdlib.h> + +#define ANIMAL 0 +#define WITH_WINGS 1 +#define WITH_LEGS 2 + +union animal; + +typedef struct +{ + int type; + char *name; + void (*print) (union animal *this); +} base; + +typedef struct +{ + int type; + char *name; + void (*print) (union animal *this); + int wings; +} with_wings; + +typedef struct +{ + int type; + char *name; + void (*print) (union animal *this); + int legs; +} with_legs; + +typedef union animal +{ + base b; + with_wings w; + with_legs l; +} animal; + +void print_with_wings (animal *this) +{ + printf ("A %s has %d wings.\n", this->b.name, this->w.wings); +} + +void print_with_legs (animal *this) +{ + printf ("A %s has %d legs.\n", this->b.name, this->l.legs); +} + +animal *new_with_wings (char *name, int wings) +{ + animal *a = malloc (sizeof (with_wings)); + a->b.type = WITH_WINGS; + a->b.name = name; + a->b.print = print_with_wings; + a->w.wings = wings; + return a; +} + +animal *new_with_legs (char *name, int legs) +{ + animal *a = malloc (sizeof (with_legs)); + a->b.type = WITH_LEGS; + a->b.name = name; + a->b.print = print_with_legs; + a->l.legs = legs; + return a; +} + +int main (void) +{ + animal *a[2] = { new_with_wings ("duck", 2), + new_with_legs ("cow", 4) }; + for (int i = 0; i < 2; i++) + a[i]->b.print (a[i]); + return 0; +} diff --git a/20210128/logo-hochschule-bochum-cvh-text-v2.pdf b/20210128/logo-hochschule-bochum-cvh-text-v2.pdf new file mode 120000 index 0000000000000000000000000000000000000000..4aa99b8f81061aca6dcaf43eed2d9efef40555f8 --- /dev/null +++ b/20210128/logo-hochschule-bochum-cvh-text-v2.pdf @@ -0,0 +1 @@ +../common/logo-hochschule-bochum-cvh-text-v2.pdf \ No newline at end of file diff --git a/20210128/logo-hochschule-bochum.pdf b/20210128/logo-hochschule-bochum.pdf new file mode 120000 index 0000000000000000000000000000000000000000..b6b9491e370e499c9276918182cdb82cb311bcd1 --- /dev/null +++ b/20210128/logo-hochschule-bochum.pdf @@ -0,0 +1 @@ +../common/logo-hochschule-bochum.pdf \ No newline at end of file diff --git a/20210128/pgscript.sty b/20210128/pgscript.sty new file mode 120000 index 0000000000000000000000000000000000000000..95c888478c99ea7fda0fd11ccf669ae91be7178b --- /dev/null +++ b/20210128/pgscript.sty @@ -0,0 +1 @@ +../common/pgscript.sty \ No newline at end of file diff --git a/20210128/pgslides.sty b/20210128/pgslides.sty new file mode 120000 index 0000000000000000000000000000000000000000..5be1416f4216f076aa268901f52a15d775e43f64 --- /dev/null +++ b/20210128/pgslides.sty @@ -0,0 +1 @@ +../common/pgslides.sty \ No newline at end of file