Skip to content
Snippets Groups Projects
Commit 6bd395f1 authored by Peter Gerwinski's avatar Peter Gerwinski
Browse files

Vorbereitung 14.12.2023

parent d48edcd3
Branches
No related tags found
No related merge requests found
Showing
with 2301 additions and 0 deletions
#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;
}
#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;
}
File added
% hp-20231214.pdf - Lecture Slides on Low-Level Programming
% Copyright (C) 2012, 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 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: Einführung
\documentclass[10pt,t]{beamer}
\usepackage{pgslides}
\usepackage{tikz}
\usepackage{rotating}
\newcommand{\redurl}[1]{\href{#1}{\color{red}\nolinkurl{#1}}}
\title{Hardwarenahe Programmierung}
\author{Prof.\ Dr.\ rer.\ nat.\ Peter Gerwinski}
\date{14.\ Dezember 2023}
\begin{document}
\maketitleframe
\title{Hardwarenahe Programmierung}
\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{Hardwarenahe Programmierung}
\item[\textbf{5}] \textbf{Algorithmen}
\begin{itemize}
\item[5.1] Differentialgleichungen
\item[5.2] Rekursion
\color{medgreen}
\item[5.3] Aufwandsabschätzungen
\end{itemize}
\item[\textbf{6}] \textbf{Objektorientierte Programmierung}
\begin{itemize}
\color{red}
\item[6.0] Dynamische Speicherverwaltung
\item[6.1] Konzepte und Ziele
\item[6.2] Beispiel: Zahlen und Buchstaben
\color{black}
\item[6.3] Unions
\item[6.4] Virtuelle Methoden
\vspace*{-\smallskipamount}
\item[\dots]
\end{itemize}
\item[\textbf{7}] \textbf{Datenstrukturen}
\end{itemize}
\end{frame}
\setcounter{section}{4}
\section{Algorithmen}
\setcounter{subsection}{2}
\subsection{Aufwandsabschätzungen \protect\color{gray}-- Komplexitätsanalyse}
\begin{frame}[fragile]
% \newcommand{\w}{\hspace*{0.75pt}}
\showsubsection
\begin{picture}(0,0)
\put(7.6,-0.5){%
\begin{minipage}[t]{5.3cm}
% \vspace*{-1.0cm}\includegraphics{landau-symbols.pdf}
\vspace*{-1.0cm}\alt<16->{\includegraphics{landau-symbols-3.pdf}}%
{\alt<15->{\includegraphics{landau-symbols-2.pdf}}%
{\includegraphics{landau-symbols.pdf}}}
\small
\begin{description}\itemsep0pt\leftskip-0.5cm
\item[$n$:] Eingabedaten
\item[$g(n)$:] Rechenzeit
\end{description}
\end{minipage}}
\end{picture}
\vspace*{-\bigskipamount}
Wann ist ein Programm "`schnell"'?
\medskip
\begin{onlyenv}<1-2>
Türme von Hanoi: $\mathcal{O}(2^n)$
\par\medskip
Für jede zusätzliche Scheibe\\verdoppelt sich die Rechenzeit!
\begin{itemize}
\arrowitem
$\frac{30,672\,\text{s}\,\cdot\,2^{32}}{3600\,\cdot\,24\,\cdot\,365,25} \approx 4174$
Jahre\\[\smallskipamount]
für 64 Scheiben
\end{itemize}
\bigskip
\end{onlyenv}
\begin{onlyenv}<2->
Faustregel:\\Schachtelung der Schleifen zählen\\
$k$ Schleifen ineinander \textarrow\ $\mathcal{O}(n^k)$
\bigskip
\end{onlyenv}
\begin{onlyenv}<3-13>
\textbf{Beispiel: Sortieralgorithmen}
\smallskip
Anzahl der Vergleiche bei $n$ Strings
\begin{itemize}
\item
Maximum suchen \pause[4]mit Schummeln\pause: $\mathcal{O}(1)$
\pause
\item
Maximum suchen\pause: $\mathcal{O}(n)$
\pause
\item
Selection-Sort\pause: $\mathcal{O}(n^2)$
\pause
\item
Bubble-Sort\pause: $\mathcal{O}(n)$ bis $\mathcal{O}(n^2)$
\pause
\item
Quicksort\pause: $\mathcal{O}(n\log n)$ bis $\mathcal{O}(n^2)$
\end{itemize}
\end{onlyenv}
\begin{onlyenv}<14>
\textbf{Wie schnell ist RSA-Verschlüsselung?}
\smallskip
\begin{math}
c = m^e\,\%\,N
\end{math}
\quad
("`$\%$"' = "`modulo"')
\medskip
\begin{lstlisting}[gobble=6,xleftmargin=2em]
int c = 1;
for (int i = 0; i < e; i++)
c = (c * m) % N;
\end{lstlisting}
\smallskip
\begin{itemize}
\item
$\mathcal{O}(e)$ Iterationen
% \item
% wenn $n$ die Anzahl der Binärziffern (Bits) von $e$ ist:
% $\mathcal{O}(2^n)$ Iterationen
\item
mit Trick:
$\mathcal{O}(\log e)$ Iterationen ($\log e$ = Anzahl der Ziffern von $e$)
\end{itemize}
\smallskip
Jede Iteration enthält eine Multiplikation und eine Division.\\
Aufwand dafür: $\mathcal{O}(\log e)$\\
\textarrow\ Gesamtaufwand: $\mathcal{O}\bigl((\log e)^2\bigr)$
\end{onlyenv}
\begin{onlyenv}<15->
\textbf{Wie schnell ist RSA?}\\
\smallskip
($n$ = typische beteiligte Zahl, z.\,B. $e,p,q$)
\begin{itemize}
\item
Ver- und Entschlüsselung (Exponentiation):\\
\strut\hbox to 3.5cm{\color{red}$\mathcal{O}\!\left((\log n)^2\right)$\hss}
\only<16->{{\color{magenta}$\mathcal{O}(n^2)$}}
\item
Schlüsselerzeugung (Berechnung von $d$):\\
\strut\hbox to 3.5cm{\color{red}$\mathcal{O}\!\left((\log n)^2\right)$\hss}
\only<16->{{\color{magenta}$\mathcal{O}(n^2)$}}
\item
Verschlüsselung brechen (Primfaktorzerlegung):\\
\strut\hbox to 3.5cm{\color{red}$\mathcal{O}\bigl(2^{\sqrt{\log n\,\cdot\,\log\log n}}\bigr)$\hss}
\only<16->{{\color{magenta}$\mathcal{O}\bigl(2^{\sqrt{n\log n}}\bigr)$}}
\end{itemize}
\vspace{0cm plus 1filll}
\textbf{Die Sicherheit von RSA beruht darauf,
daß das Brechen der Verschlüsselung aufwendiger ist als
\boldmath$\mathcal{O}\bigl((\log n)^k\bigr)$ (für beliebiges $k$).}
\vspace*{0.65cm}
\end{onlyenv}
\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{Klassenhierarchie} 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}
\iffalse
\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}
\fi
\end{document}
File added
% hp-musterloesung-20231214.pdf - Solutions to the Exercises on Low-Level Programming / Applied Computer Sciences
% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 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: Länge von Strings, Einfügen in Strings (Ergänzung)
\documentclass[a4paper]{article}
\usepackage{pgscript}
\usepackage{gnuplot-lua-tikz}
\begin{document}
\section*{Hardwarenahe Programmierung\\
Musterlösung zu den Übungsaufgaben -- 14.\ Dezember 2023}
\exercise{Dynamisches Bit-Array}
Schreiben Sie die folgenden Funktionen zur Verwaltung eines dynamischen Bit-Arrays:
\begin{itemize}
\item
\lstinline{void bit_array_init (int n)}\\
Das Array initialisieren, so daß man \lstinline{n} Bits darin speichern kann.\\
Die Array-Größe \lstinline{n} ist keine Konstante, sondern erst im laufenden Programm bekannt.\\
Die Bits sollen auf den Anfangswert 0 initialisiert werden.
\item
\lstinline{void bit_array_set (int i, int value)}\\
Das Bit mit dem Index \lstinline{i} auf den Wert \lstinline{value} setzen.\\
Der Index \lstinline{i} darf von \lstinline{0} bis \lstinline{n - 1} gehen;
der Wert \lstinline{value} darf 1 oder 0 sein.
\item
\lstinline{void bit_array_flip (int i)}\\
Das Bit mit dem Index \lstinline{i} auf den entgegengesetzten Wert setzen,\\
also auf 1, wenn er vorher 0 ist, bzw.\ auf 0, wenn er vorher 1 ist.\\
Der Index \lstinline{i} darf von \lstinline{0} bis \lstinline{n - 1} gehen.
\item
\lstinline{int bit_array_get (int i)}\\
Den Wert des Bit mit dem Index \lstinline{i} zurückliefern.\\
Der Index \lstinline{i} darf von \lstinline{0} bis \lstinline{n - 1} gehen.
\item
\lstinline{void bit_array_resize (int new_n)}\\
Die Größe des Arrays auf \lstinline{new_n} Bits ändern.\\
Dabei soll der Inhalt des Arrays, soweit er in die neue Größe paßt, erhalten bleiben.\\
Neu hinzukommende Bits sollen auf 0 initialisiert werden.
\item
\lstinline{void bit_array_done (void)}\\
Den vom Array belegten Speicherplatz wieder freigeben.
\end{itemize}
Bei Bedarf dürfen Sie den Funktionen zusätzliche Parameter mitgeben,
beispielsweise um mehrere Arrays parallel verwalten zu können.
(In der objektorientierten Programmierung wäre dies der implizite Parameter \lstinline{this},
der auf die Objekt-Struktur zeigt.)
Die Bits sollen möglichst effizient gespeichert werden,
z.\,B.\ jeweils 8 Bits in einer \lstinline{uint8_t}-Variablen.
Die Funktionen sollen möglichst robust sein,
d.\,h.\ das Programm darf auch bei unsinnigen Parameterwerten nicht abstürzen,
sondern soll eine Fehlermeldung ausgeben.
\medskip
Die folgenden \textbf{Hinweise} beschreiben
einen möglichen Weg, die Aufgabe zu lösen.
Es seht Ihnen frei, die Aufgabe auch auf andere Weise zu lösen.
\begin{itemize}
\item
Setzen Sie zunächst voraus, daß das Array die konstante Länge 8 hat,
und schreiben Sie zunächst nur die Funktionen
\lstinline{bit_array_set()}, \lstinline{bit_array_flip()} und
\lstinline{bit_array_get()}.
\item
Verallgemeinern Sie nun auf eine konstante Länge,
bei der es sich um ein Vielfaches von 8 handelt.
\item
Implementieren Sie nun die Überprüfung auf unsinnige Parameterwerte.
Damit können Sie sich gleichzeitig von der Bedingung lösen,
daß die Länge des Arrays ein Vielfaches von 8 sein muß.
\item
Gehen Sie nun von einem statischen zu einem dynamischen Array über,
und implementieren sie die Funktionen \lstinline{bit_array_init()},
\lstinline{bit_array_done()} und \lstinline{bit_array_resize()}.
\end{itemize}
% \points{14}
%
% \medskip
%
% (Hinweis für die Klausur:
% Abgabe in digitaler Form ist erwünscht, aber nicht zwingend.)
\clearpage
\solution
Die hier vorgestellte Lösung folgt den Hinweisen.
\begin{itemize}
\item
\textbf{Setzen Sie zunächst voraus, daß das Array die konstante Länge 8 hat,
und schreiben Sie zunächst nur die Funktionen
\lstinline{bit_array_set()}, \lstinline{bit_array_flip()} und
\lstinline{bit_array_get()}.}
Siehe: \gitfile{hp}{2023ws/20231214}{loesung-1-1.c}
Wir speichern in jedem der acht Bit einer \lstinline{uint8_t}-Variablen
jeweils eine Zahl, die 0 oder 1 sein kann.
Dies geschieht durch Setzen bzw.\ Löschen bzw.\ Umklappen einzelner Bits
in der Variablen.
Das Programm enthält zusätzlich eine Funktion \lstinline{output()},
mit der man sich den Inhalt des Arrays anzeigen lassen kann,
sowie ein Hauptprogramm \lstinline{main()}, um die Funktionen zu testen.
\item
\textbf{Verallgemeinern Sie nun auf eine konstante Länge,
bei der es sich um ein Vielfaches von 8 handelt.}
Siehe: \gitfile{hp}{2023ws/20231214}{loesung-1-2.c}
In diesem Programm setzen wir die Länge auf konstant \lstinline{LENGTH} Bits,
wobei es sich um eine Präprozessor-Konstante mit dem Wert 32 handelt.
Um \lstinline{LENGTH} Bits zu speichern, benötigen wir ein Array
der Länge \lstinline{LENGTH / 8} Bytes.
Um auf ein einzelnes Bit zuzugreifen, müssen wir zunächst ermitteln,
in welchem der Bytes sich befindet. Außerdem interessieren wir uns
für die Nummer des Bits innerhalb des Bytes.
Den Array-Index des Bytes erhalten wir, indem wir den Index des Bits
durch 8 dividieren. Der bei dieser Division verbleibende Rest ist die
Nummer des Bits innerhalb des Bytes.
Diese Rechnungen führen wir in den drei Funktionen
\lstinline{bit_array_set()}, \lstinline{bit_array_flip()} und
\lstinline{bit_array_get()} durch.
(Diese ist eine eher unelegante Code-Verdopplung -- hier sogar eine Verdreifachung.
Für den Produktiveinsatz lohnt es sich, darüber nachzudenken,
wie man diese vermeiden kann, ohne gleichzeitig an Effizienz einzubüßen.
Hierfür käme z.\,B.\ ein Präprozessor-Makro in Frage.
Für die Lösung der Übungsaufgabe wird dies hingegen nicht verlangt.)
\item
\textbf{Implementieren Sie nun die Überprüfung auf unsinnige Parameterwerte.
Damit können Sie sich gleichzeitig von der Bedingung lösen,
daß die Länge des Arrays ein Vielfaches von 8 sein muß.}
Siehe: \gitfile{hp}{2023ws/20231214}{loesung-1-3.c}
Um weitere Code-Verdopplungen zu vermeiden,
führen wir eine Funktion \lstinline{check_index()} ein,
die alle Prüfungen durchführt.
Wenn die Länge des Arrays kein Vielfaches von 8 ist,
wird das letzte Byte nicht vollständig genutzt.
Die einzige Schwierigkeit besteht darin, die korrekte Anzahl von Bytes
zu ermitteln, nämlich die Länge dividiert durch 8, aber nicht ab-, sondern
aufgerundet. Am elegantesten geht dies durch vorherige Addition von 7:
\lstinline{#define BYTES ((LENGTH + 7) / 8)}.
Es ist aber auch zulässig, die Anzahl der Bytes mit Hilfe einer
\lstinline{if}-Anweisung zu ermitteln: Länge durch 8 teilen und abrunden;
falls die Division nicht glatt aufging, um 1 erhöhen.
\item
\textbf{Gehen Sie nun von einem statischen zu einem dynamischen Array über,
und implementieren sie die Funktionen \lstinline{bit_array_init()},
\lstinline{bit_array_done()} und \lstinline{bit_array_resize()}.}
Siehe: \gitfile{hp}{2023ws/20231214}{loesung-1-4.c}.
Damit ist die Aufgabe gelöst.
Aus den Präprozessor-Konstanten \lstinline{LENGTH} und \lstinline{BYTES}
werden nun globale \lstinline{int}-Variable.
Die Funktion \lstinline{bit_array_init()} berechnet die korrekten Werte
für diese Variablen und legt das Array mittels \lstinline{malloc()} dynamisch
an. Eine Größenänderung des Arrays erfolgt mittels \lstinline{realloc()},
das Freigeben mittels \lstinline{free()}.
Das Programm setzt Variable, die aktuell nicht verwendet werden,
auf den Wert \lstinline{0} bzw.\ \lstinline{NULL}.
Dies ermöglicht es der Funktion \lstinline{check_index()},
auch zu prüfen, ob das Array vorher korrekt mit \lstinline{bit_array_init()}
erzeugt wurde -- oder ob es vielleicht schon wieder mit
\lstinline{bit_array_done()} freigegeben wurde.
\end{itemize}
\clearpage
\exercise{Objektorientierte Tier-Datenbank}
Das unten dargestellte Programm (Datei: \gitfile{hp}{2023ws/20231214}{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 in Rot dargestellten Ersetzungen vor\\
(Datei: \gitfile{hp}{2023ws/20231214}{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}{2023ws/20231214}{loesung-2d-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}{2023ws/20231214}{loesung-2d-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}{2023ws/20231214}{loesung-2d-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}{2023ws/20231214}{loesung-2e.c}.
Diese Lösung basiert auf \gitfile{hp}{2023ws/20231214}{loesung-2d-2.c},
da diese bereits weniger explizite Typumwandlungen enthält
als \gitfile{hp}{2023ws/20231214}{loesung-2d-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}{2023ws/20231214}{loesung-2f.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}{2023ws/20231214}{loesung-2g.c}.
\end{itemize}
\end{document}
File added
% hp-uebung-20231214.pdf - Exercises on Low-Level Programming / Applied Computer Sciences
% Copyright (C) 2013, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 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: dynamisches Bit-Array, objektorientierte Tier-Datenbank
\documentclass[a4paper]{article}
\usepackage{pgscript}
\usepackage{gensymb}
\newcommand{\ItwoC}{I\raisebox{0.5ex}{\footnotesize 2}C}
\newcommand{\ITWOC}{I\raisebox{0.5ex}{\normalsize 2}C}
\begin{document}
\thispagestyle{empty}
\section*{Hardwarenahe Programmierung\\
Übungsaufgaben -- 14.\ Dezember 2023}
Diese Übung enthält Punkteangaben wie in einer Klausur.
Um zu "`bestehen"', müssen Sie innerhalb von 80 Minuten
unter Verwendung ausschließlich zugelassener Hilfsmittel
14 Punkte (von insgesamt \totalpoints) erreichen.
\exercise{Dynamisches Bit-Array}
Schreiben Sie die folgenden Funktionen zur Verwaltung eines dynamischen Bit-Arrays:
\begin{itemize}
\item
\lstinline{void bit_array_init (int n)}\\
Das Array initialisieren, so daß man \lstinline{n} Bits darin speichern kann.\\
Die Array-Größe \lstinline{n} ist keine Konstante, sondern erst im laufenden Programm bekannt.\\
Die Bits sollen auf den Anfangswert 0 initialisiert werden.
\item
\lstinline{void bit_array_set (int i, int value)}\\
Das Bit mit dem Index \lstinline{i} auf den Wert \lstinline{value} setzen.\\
Der Index \lstinline{i} darf von \lstinline{0} bis \lstinline{n - 1} gehen;
der Wert \lstinline{value} darf 1 oder 0 sein.
\item
\lstinline{void bit_array_flip (int i)}\\
Das Bit mit dem Index \lstinline{i} auf den entgegengesetzten Wert setzen,\\
also auf 1, wenn er vorher 0 ist, bzw.\ auf 0, wenn er vorher 1 ist.\\
Der Index \lstinline{i} darf von \lstinline{0} bis \lstinline{n - 1} gehen.
\item
\lstinline{int bit_array_get (int i)}\\
Den Wert des Bit mit dem Index \lstinline{i} zurückliefern.\\
Der Index \lstinline{i} darf von \lstinline{0} bis \lstinline{n - 1} gehen.
\item
\lstinline{void bit_array_resize (int new_n)}\\
Die Größe des Arrays auf \lstinline{new_n} Bits ändern.\\
Dabei soll der Inhalt des Arrays, soweit er in die neue Größe paßt, erhalten bleiben.\\
Neu hinzukommende Bits sollen auf 0 initialisiert werden.
\item
\lstinline{void bit_array_done (void)}\\
Den vom Array belegten Speicherplatz wieder freigeben.
\end{itemize}
Bei Bedarf dürfen Sie den Funktionen zusätzliche Parameter mitgeben,
beispielsweise um mehrere Arrays parallel verwalten zu können.
(In der objektorientierten Programmierung wäre dies der implizite Parameter \lstinline{this},
der auf die Objekt-Struktur zeigt.)
Die Bits sollen möglichst effizient gespeichert werden,
z.\,B.\ jeweils 8 Bits in einer \lstinline{uint8_t}-Variablen.
Die Funktionen sollen möglichst robust sein,
d.\,h.\ das Programm darf auch bei unsinnigen Parameterwerten nicht abstürzen,
sondern soll eine Fehlermeldung ausgeben.
\medskip
Die folgenden \textbf{Hinweise} beschreiben
einen möglichen Weg, die Aufgabe zu lösen.
Es seht Ihnen frei, die Aufgabe auch auf andere Weise zu lösen.
\begin{itemize}
\item
Setzen Sie zunächst voraus, daß das Array die konstante Länge 8 hat,
und schreiben Sie zunächst nur die Funktionen
\lstinline{bit_array_set()}, \lstinline{bit_array_flip()} und
\lstinline{bit_array_get()}.
\item
Verallgemeinern Sie nun auf eine konstante Länge,
bei der es sich um ein Vielfaches von 8 handelt.
\item
Implementieren Sie nun die Überprüfung auf unsinnige Parameterwerte.
Damit können Sie sich gleichzeitig von der Bedingung lösen,
daß die Länge des Arrays ein Vielfaches von 8 sein muß.
\item
Gehen Sie nun von einem statischen zu einem dynamischen Array über,
und implementieren Sie die Funktionen \lstinline{bit_array_init()},
\lstinline{bit_array_done()} und \lstinline{bit_array_resize()}.
\end{itemize}
\points{14}
\medskip
(Hinweis für die Klausur:
Abgabe in digitaler Form ist erwünscht, aber nicht zwingend.)
\clearpage
\exercise{Objektorientierte Tier-Datenbank}
Das unten dargestellte Programm (Datei: \gitfile{hp}{2023ws/20231214}{aufgabe-2a.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 in Rot dargestellten Ersetzungen vor
(Datei: \gitfile{hp}{2023ws/20231214}{aufgabe-2b.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}
../common/landau-symbols-2.pdf
\ No newline at end of file
../common/landau-symbols-3.pdf
\ No newline at end of file
../common/landau-symbols.pdf
\ No newline at end of file
#include <stdio.h>
#include <stdint.h>
uint8_t buffer = 0;
void bit_array_set (int i, int value)
{
uint8_t mask = 1 << i;
if (value)
buffer |= mask;
else
buffer &= ~mask;
}
void bit_array_flip (int i)
{
uint8_t mask = 1 << i;
buffer ^= mask;
}
int bit_array_get (int i)
{
uint8_t mask = 1 << i;
if (buffer & mask)
return 1;
else
return 0;
}
void output (void)
{
for (int i = 0; i < 8; i++)
{
if (i % 4 == 0)
printf (" ");
printf ("%d", bit_array_get (i));
}
printf ("\n");
}
int main (void)
{
output ();
bit_array_set (2, 1);
output ();
bit_array_flip (7);
output ();
bit_array_set (2, 0);
output ();
}
#include <stdio.h>
#include <stdint.h>
#define LENGTH 32
uint8_t buffer[LENGTH / 8] = { 0, 0, 0, 0 };
void bit_array_set (int i, int value)
{
int byte_index = i / 8;
int bit_index = i % 8;
uint8_t mask = 1 << bit_index;
if (value)
buffer[byte_index] |= mask;
else
buffer[byte_index] &= ~mask;
}
void bit_array_flip (int i)
{
int byte_index = i / 8;
int bit_index = i % 8;
uint8_t mask = 1 << bit_index;
buffer[byte_index] ^= mask;
}
int bit_array_get (int i)
{
int byte_index = i / 8;
int bit_index = i % 8;
uint8_t mask = 1 << bit_index;
if (buffer[byte_index] & mask)
return 1;
else
return 0;
}
void output (void)
{
for (int i = 0; i < LENGTH; i++)
{
if (i % 4 == 0)
printf (" ");
printf ("%d", bit_array_get (i));
}
printf ("\n");
}
int main (void)
{
output ();
bit_array_set (12, 1);
output ();
bit_array_flip (31);
output ();
bit_array_set (12, 0);
output ();
}
#include <stdio.h>
#include <stdint.h>
#include <error.h>
#define LENGTH 29
#define BYTES ((LENGTH + 7) / 8)
uint8_t buffer[BYTES] = { 0, 0, 0, 0 };
void check_index (int i)
{
if (i < 0 || i >= LENGTH)
error (1, 0, "index %d out of range (0, ..., %d)", i, LENGTH - 1);
}
void bit_array_set (int i, int value)
{
check_index (i);
int byte_index = i / 8;
int bit_index = i % 8;
uint8_t mask = 1 << bit_index;
if (value)
buffer[byte_index] |= mask;
else
buffer[byte_index] &= ~mask;
}
void bit_array_flip (int i)
{
check_index (i);
int byte_index = i / 8;
int bit_index = i % 8;
uint8_t mask = 1 << bit_index;
buffer[byte_index] ^= mask;
}
int bit_array_get (int i)
{
check_index (i);
int byte_index = i / 8;
int bit_index = i % 8;
uint8_t mask = 1 << bit_index;
if (buffer[byte_index] & mask)
return 1;
else
return 0;
}
void output (void)
{
for (int i = 0; i < LENGTH; i++)
{
if (i % 4 == 0)
printf (" ");
printf ("%d", bit_array_get (i));
}
printf ("\n");
}
int main (void)
{
output ();
bit_array_set (12, 1);
output ();
bit_array_flip (28);
output ();
bit_array_set (12, 0);
output ();
bit_array_flip (31);
output ();
}
#include <stdio.h>
#include <stdint.h>
#include <error.h>
#include <stdlib.h>
int length = 0;
int bytes = 0;
uint8_t *buffer = NULL;
void bit_array_init (int n)
{
length = n;
bytes = (length + 7) / 8;
if (buffer)
free (buffer);
buffer = malloc (bytes * sizeof (uint8_t));
for (int i = 0; i < bytes; i++)
buffer[i] = 0;
}
void bit_array_resize (int new_n)
{
length = new_n;
bytes = (length + 7) / 8;
buffer = realloc (buffer, bytes * sizeof (uint8_t));
}
void bit_array_done (void)
{
free (buffer);
buffer = NULL;
length = 0;
bytes = 0;
}
void check_index (int i)
{
if (!buffer)
error (1, 0, "array not initialised");
if (i < 0 || i >= length)
error (1, 0, "index %d out of range (0, ..., %d)", i, length - 1);
}
void bit_array_set (int i, int value)
{
check_index (i);
int byte_index = i / 8;
int bit_index = i % 8;
uint8_t mask = 1 << bit_index;
if (value)
buffer[byte_index] |= mask;
else
buffer[byte_index] &= ~mask;
}
void bit_array_flip (int i)
{
check_index (i);
int byte_index = i / 8;
int bit_index = i % 8;
uint8_t mask = 1 << bit_index;
buffer[byte_index] ^= mask;
}
int bit_array_get (int i)
{
check_index (i);
int byte_index = i / 8;
int bit_index = i % 8;
uint8_t mask = 1 << bit_index;
if (buffer[byte_index] & mask)
return 1;
else
return 0;
}
void output (void)
{
for (int i = 0; i < length; i++)
{
if (i % 4 == 0)
printf (" ");
printf ("%d", bit_array_get (i));
}
printf ("\n");
}
int main (void)
{
bit_array_init (29);
output ();
bit_array_set (12, 1);
output ();
bit_array_flip (28);
output ();
bit_array_set (12, 0);
output ();
bit_array_flip (31);
output ();
bit_array_done ();
}
#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;
}
#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;
}
#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;
}
#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;
}
#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;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment