d) Welche Aussage zu volatile ist richtig?

Ähnliche Dokumente
Zeiger vom Typ (void *) sind am besten für Zeigerarithmetik geeignet, da sie kompatibel zu jedem Zeigertyp sind.

Zeiger vom Typ (void *) sind am besten für Zeigerarithmetik geeignet, da sie kompatibel zu jedem Zeigertyp sind.

f) Was versteht man beim Zugriff auf I/O-Register unter dem Begriff "Memory-mapped"?

b) Was bewirken folgende Programmanweisungen? uint8_t x = 42; x ^= x;

d) Was passiert, wenn das folgende Programmstück übersetzt und ausgeführt

d) Welche Aussage zum Thema virtueller Adressraum ist richtig?

d) Welche Aussage zu Zeigern ist richtig? Beim Rechnen mit Zeigern wird immer der Typ des Zeigers beachtet.

b) Gegeben sei folgende Enumeration: enum SPRACHE {Deutsch, Englisch, Russisch};

Grundlagen der Informatik 2 Modul Systemnahe Programmierung in C (SPiC) Klausur am 25. Juli 2008

a) Welche Aussage zu Zeigern ist richtig? Die Übergabesemantik für Zeiger als Funktionsparameter ist callby-value.

Zeiger vom Typ (void *) sind am besten für Zeigerarithmetik geeignet, da sie kompatibel zu jedem Zeigertyp sind.

e) Welchen Wert hat die Variable i nach Ausführung der folgenden Zeilen Code: x25 0x84 b) Welche Aussage zu folgender Funktion ist richtig?

A B C D E C 5 7 D 3 E. 2. [6-Bit, positiv] Welche Dezimalzahl wird durch die gegebene Bit-Sequenz kodiert?

Friedrich-Alexander-Universität Erlangen-Nürnberg

U5-2 Register beim AVR-µC

GdI2 - Systemnahe Programmierung in C Übungen Jürgen Kleinöder Universität Erlangen-Nürnberg Informatik 4, 2006 U4.fm

Inhalt. Übungen zu Systemnahe Programmierung in C (SPiC) Implementierung von Interruptbehandlungen. Interrupts

U5 Fortgeschrittene AVR-Programmierung

Zeiger vom Typ void* benötigen weniger Speicher als andere Zeiger, da bei anderen Zeigertypen zusätzlich die Größe gespeichert werden muss.

U5 Fortgeschrittene AVR-Programmierung U5 Fortgeschrittene AVR-Programmierung. Synchronisation mit Unterbrechungsbehandlungen

U2 Fortgeschrittene AVR-Programmierung. U2-1 Externe Interrupts des AVR-μC. 1 Flanken-/Pegel-Steuerung. 1 Flanken-/Pegel-Steuerung (2) 2 Maskieren

myavr Programmierung in C

b) Gegeben sei folgende Enumeration: enum SPRACHE {Deutsch, Englisch, Russisch};

Übungen zu Systemnahe Programmierung in C (SPiC)

Atmega Interrupts. Rachid Abdallah Gruppe 3 Betreuer : Benjamin Bös

Übungen zu Systemnahe Programmierung in C (SPiC) Inhalt. Moritz Strübe, Rainer Müller (Lehrstuhl Informatik 4) Sommersemester 2014

Grundlagen der Informatik 2 Modul Systemnahe Programmierung in C (SPiC) Klausur am 9. April 2008

Übungen zu Systemnahe Programmierung in C (SPiC)

Wiederholung: Zugriff auf AVR-Prozessor-Register. Aufgabe 3: 7seg-Modul der SPiCboard-Bibliothek

Übungen zu Systemnahe Programmierung in C (SPiC)

Inhalt. Übungen zu Systemnahe Programmierung in C (SPiC) Schnittstellenbeschreibung. Inhalt

U3-1 Register beim AVR-μC. U3 3. Übung. U3-2 I/O-Ports des AVR-μC. 1 Überblick. 2 Makros für Register-Zugriffe. 1 Überblick

Wiederholung: Zugriff auf AVR-Prozessor-Register. Aufgabe 3: 7seg-Modul der SPiCboard-Bibliothek

Wiederholung: Zugriff auf AVR-Prozessor-Register

d) Welche Aussage zum Thema Adressräume ist richtig?

Mikrocontrollerplatine vorbereiten

Übungen zu Systemnahe Programmierung in C (SPiC) Wintersemester 2018/19

U3 3. Übung U3 3. Übung. Systemnahe Programmierung in C Übungen Moritz Strübe Universität Erlangen-Nürnberg Informatik 4, 2009 U3.fm

Besprechung Aufgabe 1. Pointer. Register und Ports. SPiC - Ü U3.1

U3 UNIX-Signale U3 UNIX-Signale

IR NEC Empfänger mit 4x7 LED Anzeige (ATtiny2313)

Inhalt. Übungen zu Systemnahe Programmierung in C (SPiC) Inhalt. Globale Variablen

Einführung in die Programmiersprache C

Inhalt. Übungen zu Systemnahe Programmierung in C (SPiC) Interrupts. Inhalt. Interrupts. Synchronisation

Übungen zu Grundlagen der systemnahen Programmierung in C (GSPiC) im Wintersemester 2017/18

U2-1 Register beim AVR- C. U2-2 I/O-Ports des AVR- C. 1 Überblick. 2 Makros für Register-Zugriffe. 1 Überblick

Übungen zu Systemnahe Programmierung in C (SPiC)

Dem Vater-Prozess wird die Prozess-ID des Kind-Prozesses zurückgeliefert.

Einführung in die Programmiersprache C

(Ausnahmebehandlung)

Inhalt. Übungen zu Systemnahe Programmierung in C (SPiC) Inhalt

8.3 Taster am µcontroller

Sebastian Maier (Lehrstuhl Informatik 4) Übung 4. Sommersemester 2017

Probeklausur Name: (c)

WS 2016/17 Viel Erfolg!!

Programmierung mit C Zeiger

Makros sind Textersetzungen, welche vom Präprozessor aufgelöst werden. Dies Passiert bevor der Compiler die Datein verarbeitet.

Übungen zu Systemnahe Programmierung in C (SPiC) Wintersemester 2017/18

Globale Variablen Diverses. Globale Variablen. Globale Variablen

Übersicht. Speichertypen. Speicherverwaltung und -nutzung. Programmieren in C

Klausur: Informatik I am 06. Februar 2009 Gruppe: D Dirk Seeber, h_da, Fb Informatik. Nachname: Vorname: Matr.-Nr.: Punkte:

d) Welche Aussage über exec() ist richtig?

Vorbereitung. Teil D Analog-Digital-Wandler 1

Unter einem Interrupt kann man sich einen durch Hardware ausgelösten Unterprogrammaufruf vorstellen.

Inhalt. Aufgabe 4: LED-Modul Hinweise Testen des Moduls Sommersemester 2015

Klausur: Grundlagen der Informatik I, am 06. Februar 2009 Dirk Seeber, h_da, Fb Informatik. Nachname: Vorname: Matr.-Nr.: Punkte:

Vorlesung Programmieren

Übungen zu Systemnahe Programmierung in C (SPiC) Wintersemester 2017/18

Erste Schritte der Programmierung in C

Die Grösse der primitiven Datentypen in C ist architekturabhängig

Programmieren in C. Speicher anfordern, Unions und Bitfelder. Prof. Dr. Nikolaus Wulff

Verwendung Vereinbarung Wert einer Funktion Aufruf einer Funktion Parameter Rekursion. Programmieren in C

Teilprüfung Software- und Internettechnologie Programmierkurs 2 Wintersemester 2004/2005

C/C++-Programmierung

f) Was versteht man beim Zugriff auf I/O-Register unter dem Begriff "Memory-mapped"?

V cc. 1 k. 7 mal 150 Ohm

D.1 Vorbereitung. Teil D Analog-Digital-Wandler 1

#include "C:\Users\media\Desktop\Harri\Technik\Elektronik\Projekte\Stiftuhr\Servotest\servotest\servotest.h"

WS 2017/18 Viel Erfolg!!

Klausur: Informatik, am 11. Juli 2013 Gruppe: B Dirk Seeber, h_da, Fb Informatik. Nachname: Vorname: Matr.-Nr.: Punkte:

Arduino Kurs Bits und Bytes. Stephan Laage-Witt FES Lörrach

e) Welche Aussage zu Speicherzuteilungsverfahren ist falsch?

Für den Anschluss dieses und anderer Module dieser Serie an das myavr Board steht ein Adapter zur Verfügung.

Name : Klasse : Punkte : Note :

E Mikrocontroller-Programmierung

Lotto. eine Projektarbeit in DVT. von Sven Schwab

Vorlesung Objektorientierte Programmierung Klausur

Starten Sie die Arduino IDE und geben Sie den folgenden Programmcode ein:

Übungspaket 29 Dynamische Speicherverwaltung: malloc() und free()

Einführung in die Programmierung von Mikrocontrollern mit C/C++

Studiengang Maschinenbau, Schwerpunkt Mechatronik (früher: Automatisierungstechnik) Seite 1 von 8

Klausur: Informatik, am 11. Juli 2013 Gruppe: A Dirk Seeber, h_da, Fb Informatik. Nachname: Vorname: Matr.-Nr.: Punkte:

Microcontroller Praktikum SS2010 Dipl. Ing. R. Reisch

PIC16 Programmierung in HITECH-C

RalfPongratz. Grundversion. Reaktivlichtmit7SegmentAnzeige

Übungen zu Softwaresysteme I Jürgen Kleinöder Universität Erlangen-Nürnberg Informatik 4, 2004 E-Uebung3.fm

System-Makro in time.h : #define CLOCKS_PER_SEC 1000 Frühere Makro-Bezeichnung (z.t. noch gebräuchlich): #define CLK_TCK CLOCKS_PER_SEC//aus:time.

Transkript:

Aufgabe 1: (18 Punkte) Bei den Multiple-Choice-Fragen ist jeweils nur eine richtige Antwort eindeutig anzukreuzen. Auf die richtige Antwort gibt es die angegebene Punktzahl. Wollen Sie eine Multiple-Choice-Antwort korrigieren, streichen Sie bitte die falsche Antwort mit drei waagrechten Strichen durch ( )und kreuzen die richtige an. Lesen Sie die Frage genau, bevor Sie antworten. a) Was versteht man unter Nebenläufigkeit? Wenn ein Programm abwechselnd auf zwei verschiedene Speicherbereiche zugreift. Wenn ein Programmabschnitt in einer Schleife mehrfach durchlaufen wird. Die Programmabschnitte im if- und else-teil einer bedingten Anweisung. Wenn für zwei Befehle aus zwei Programmabläufen nicht feststeht, welcher von beiden tatsächlich zuerst ausgeführt werden wird. b) Wie löst man das Nebenläufigkeitsproblem "lost-update" zwischen Hauptprogramm und Interrupthandler auf einem Mikrocontroller? Durch die Verwendung von pegelgesteuerten anstelle von flankengesteuerten Interrupts Durch den Aufruf einer Callback-Funktion im Interrupthandler Durch Synchronisation mittels kurzzeitigem Sperren der Interrupts Die Verwendung des Schlüsselwortes volatile löst alle Nebenläufigkeitsprobleme c) Wie viele Bytes belegt die folgende Struktur im Speicher eines AVR-Mikrocontrollers: union { struct { uint8_t lo, hi; }; uint16_t r16; } reg; 2 Bytes 4 Bytes 16 Bytes 32 Bytes d) Welche Aussage zu volatile ist richtig? Das Schlüsselwort volatile hat nur noch eine historische Bedeutung und ist in heutigen Programmen nicht mehr nötig. Das Schlüsselwort volatile unterbindet Optimierungen an einer damit definierten Variable. Das Schlüsselwort volatile unterbindet alle Nebenläufigkeitsprobleme. Das Schlüsselwort volatile erlaubt dem Compiler bessere Optimierungen durchzuführen. e) Was ist ein Stack-Frame? Der Speicherbereich, in dem der Programmcode einer Funktion abgelegt ist. Ein spezieller Registersatz des Prozessors zur Bearbeitung von Funktionen. Ein Fehler, der bei unberechtigten Zugriffen auf den Stack-Speicher entsteht. Ein Bereich des Speichers, in dem u.a. lokale automatic-variablen einer Funktion abgelegt sind. f) Welche der folgenden Aussagen zum Begriff der Rücksprungadresse ist richtig? Bei Aufruf einer Funktion sichert der Prozessor selbsttätig die Adresse der folgenden Instruktion. Dies ist die Rücksprungadresse. Die Rücksprungadresse ermöglicht die Rückkehr ins Betriebssystem. Auf einer Mikrocontroller-Plattform ist sie allerdings nicht vorhanden. Bei Aufruf einer Funktion über einen Funktionszeiger muss der Programmierer eine Rücksprungadresse angeben, an der das Programm später fortgesetzt werden soll. Bei rekursiven Funktionsaufrufen erstellt der Compiler eine Rücksprungadresse um sicher zu stellen, dass die Rekursion terminiert. - 3 von 18 - - 4 von 18 -

g) Gegeben ist folgender Programmcode: #define SUB(a,b) a-b #define ADD(a,b) a+b Was ist das Ergebnis des folgenden Ausdrucks? 2 * SUB(2, ADD(3, 4)) -10-3 5 6 h) In welchen Situationen wird ein Prozess in den Zustand "blockiert" versetzt? während der Prozesserzeugung solange die Verwaltungsstrukturen noch nicht angelegt sind bei jedem Aufruf der V-Operation eines Semaphors wenn er ausgeführt werden könnte, aber ein anderer Prozess die CPU zugeteilt bekommen soll beim Lesen eines Zeichens von der Tastatur, so lange keine Taste gedrückt wird i) Welche Angaben enthält ein Eintrag eines Katalogs (Verzeichnisses) in einem Standard-UNIX-Dateisystem? Blocknummer des Inode-Plattenblocks und Dateiname Inode-Nummer und Dateiname Dateiname, Dateigröße, Eigentümer und Zugriffsrechte nur die Inode-Nummer 3 Aufgabe 2a: Airbagsteuerung (30 Punkte) Sie dürfen diese Seite zur besseren Übersicht bei der Programmierung heraustrennen! Schreiben Sie ein Programm für den AVR-Mikrocontroller, das Messwerte von einem Verzögerungssensor entgegen nimmt und bei Überschreitung eines vorgegebenen Grenzwertes den Airbag auslöst. Die Airbagsteuerung bekommt hierfür Interrupts des Verzögerungssensors, sobald neue Messwerte zum Auslesen zur Verfügung stehen. Wird über einen vordefinierten Zeitraum kein Messwert vom Sensor zur Verfügung gestellt, dann wird dies mit Hilfe eines Watchdog-Timers erkannt und in einen Fehlerzustand gewechselt, der durch eine LED visualisiert wird. Im Detail soll Ihr Programm wie folgt funktionieren: Initialisieren Sie die Hardware in der Funktion void init(void), so dass auch die LED für die Fehleranzeige ausgeschaltet ist. Treffen Sie keine Annahmen über den initialen Zustand der Hardware-Register. Zu Beginn prüft das Programm einmalig, ob der Airbag einsatzbereit ist. Wurde der Airbag bereits ausgelöst, wechselt das Programm durch Aufruf von error() in den Fehlermodus. Implementieren Sie hierfür die Funktion void error(void); welche die LED zur Fehleranzeige aktiviert und anschließend in einer Endlosschleife wartet. Ist der Airbag einsatzbereit, wird der Watchdog-Timer aktiviert, der später zur Erkennung von Fehlfunktionen des Sensors dient. Hierfür muss eine Behandlungsfunktion mit der Signatur void handler(void); durch Aufruf der vorgegebenen Bibliotheksfunktion void registerwatchdog(void (*func_ptr) (void)); registriert werden. Anschließend geht das Programm in den Steuerungsbetrieb über, in dem der Mikrocontroller im stromsparenden Schlafmodus auf Ereignisse von Sensor oder Watchdog wartet. Steht ein neuer Messwert des Verzögerungssensors zur Verfügung, so wird das durch einen Interrupt signalisiert. Der vorzeichenlose 16-Bit Messwert kann dann aus den beiden Registern SENSOR_LOW und SENSOR_HIGH ausgelesen werden. Wurde der Messwert abgeholt, muss dies dem Sensor durch Schreiben des Registers SENSOR_RESET mit dem Wert 1 mitgeteilt werden. Aus Latenzgründen muss das Auslesen und Zurücksetzen im Interrupt-Handler stattfinden. Nachdem ein neuer Messwert gelesen wurde, prüft das Hauptprogramm ob der Grenzwert der maximalen Verzögerung überschritten wurde. Ist dies der Fall, so wird der Airbag ausgelöst und anschließend in den Fehlermodus gewechselt. In regelmäßigen Abständen wird der Watchdog-Timer ausgelöst, dessen Handler im Interruptkontext ausgeführt wird. Wurde seit dem vorhergehenden Watchdog-Ereignis kein Sensorwert empfangen, ist von einer Fehlfunktion des Sensors auszugehen und das Hauptprogramm wechselt in den Fehlermodus. - 5 von 18 - - 6 von 18 -

Information über die Hardware Sie dürfen diese Seite zur besseren Übersicht bei der Programmierung heraustrennen! LED für Fehleranzeige: PORTB, Pin 5 - active-low: Die LED leuchtet sobald ein LOW-Pegel anliegt. - Pin als Ausgang konfigurieren: entsprechendes Bit in DDRB-Register auf 1 - LED zu Beginn ausschalten; entsprechendes Bit in PORTB-Register auf 1 Verzögerungssensor: Interruptleitung INT0 an PORTD, Pin 2 - active-low: steht ein neuer Messwert zur Verfügung, so liegt ein LOW-Pegel an - Pin als Eingang konfigurieren, entsprechendes Bit in DDRD-Register auf 0 - Internen Pull-Up-Widerstand aktivieren; entsprechendes Bit in PORTD-Register auf 1 - Externe Interruptquelle INT0, ISR-Vektor-Makro INT0_vect - Aktivierung der Interruptquelle erfolgt durch Setzen des INT0-Bits im Register GICR - Abfrage des aktuellen 16-Bit Messwertes durch Auslesen von Register SENSOR_HIGH (oberes Byte) und SENSOR_LOW (unteres Byte) - Sensor für erneute Messung zurücksetzen durch Schreiben in Register SENSOR_RESET mit Wert 1 - Das Auslesen und das Zurücksetzen des Sensors muss im Interruptkontext stattfinden Airbag Statusabfrage: PORTB, Pin 6 - active-low: Ist der Airbag einsatzbereit, so liegt ein LOW-Pegel an - Pin als Eingang konfigurieren: entsprechendes Bit in DDRB-Register auf 0 - Internen Pull-Up-Widerstand aktivieren; entsprechendes Bit in PORTB-Register auf 1 Airbag Auslösung: PORTB, Pin 7 - active-high: Der Airbag wird ausgelöst, wenn ein HIGH-Pegel anliegt - Pin als Ausgang konfigurieren: entsprechendes Bit in DDRB-Register auf 1 - Verfrühte Aktivierung des Airbags verhindern; entsprechendes Bit in PORTB-Register auf 0 Konfiguration der externen Interruptquellen 0 und 1 (Bits in Register MCUCR) Interrupt 0 Interrupt 1 Beschreibung ISC01 ISC00 ISC11 ISC10 0 0 Interrupt bei low Pegel 0 0 0 1 Interrupt bei beliebiger Flanke 0 1 1 0 Interrupt bei fallender Flanke 1 0 1 1 Interrupt bei steigender Flanke 1 1 #include <avr/io.h> #include <avr/interrupt.h> #include <avr/sleep.h> #include <stdint.h> // Grenzwert der Verzoegerung #define DECELERATION_THRESHOLD (0x1AD3) // Verzoegerungssensor #define SENSOR_LOW #define SENSOR_HIGH #define SENSOR_RESET (*((volatile uint8_t *)0xa0)) (*((volatile uint8_t *)0xb0)) (*((volatile uint8_t *)0xc0)) /* Bibliotheksfunktionen */ void registerwatchdog(void (*func_ptr) (void)); /* Funktionsdeklarationen, globale Variablen, etc. */ static void init(void); static void error(void); /* Unterbrechungsbehandlungsfunktion / Watchdog-Handler */ Ergänzen Sie das folgende Codegerüst so, dass ein vollständig übersetzbares Programm entsteht. A: - 7 von 18 - - 8 von 18 -

/* Funktion main */ /* Ereignis "neuer Sensorwert" bearbeiten */ /* Initialisierung und lokale Variablen */ /* Hauptschleife */ /* Warten auf Ereignisse */ /* Watchdog-Ereignis bearbeiten */ B: /* Ende main */ E: - 9 von 18 - - 10 von 18 -

/* Funktion error */ Aufgabe 2b: Programm linecount (15 Punkte) Sie dürfen diese Seite zur besseren Übersicht bei der Programmierung heraustrennen! Schreiben Sie ein Programm linecount, das die Gesamtanzahl der Zeilen aller auf der Befehlszeile übergebenen regulären Dateien ermittelt. Der Aufruf des Programms erfolgt mit einer Liste von Dateien als Parameter, zum Beispiel:./linecount foo.txt bar.c baz.html /* Ende error */ /* Initialisierungsfunktion */ Das Programm soll im Detail wie folgt funktionieren: Das Programm prüft zu Beginn, ob mindestens ein Dateiname als Parameter übergeben wurde. Sollte dies nicht der Fall sein, gibt es eine entsprechende Fehlermeldung aus und beendet sich. Wurde das Programm korrekt aufgerufen, wird die Liste der übergebenen Dateinamen durchlaufen, wobei jedes Argument einzeln verarbeitet wird. Wenn es sich bei einem übergebenem Argument um eine reguläre Datei handelt, wird mit Hilfe der Funktion flcount() die Anzahl der Zeilen ermittelt, welche im Erfolgsfall zur Gesamtzahl addiert wird. Die Funktion int flcount(const char *filename); öffnet die übergebene Datei und zählt die Anzahl der Zeilen. Im Fehlerfall wird ein negativer Wert zurückgegeben, im Erfolgsfall die Anzahl der Zeilen dieser Datei. Nach Verarbeitung aller Argumente gibt das Programm die Summe der Zeilen aller Dateien aus. Hinweise: Achten Sie auf eine korrekte Fehlerbehandlung der verwendeten Funktionen. Die Ausgabe von Fehlern soll mit Hilfe der errno-variable auf dem stderr-kanal erfolgen. Eine Zeile wird immer mit dem Zeichen \n terminiert. Ergänzen Sie das folgende Codegerüst so, dass ein vollständig übersetzbares Programm entsteht. FI: - 11 von 18 - - 12 von 18 -

#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <sys/stat.h> // Funktion main // Funktion flcount C: // Ende main M: - 13 von 18 - - 14 von 18 -

Aufgabe 3: Module (6 Punkte) Die folgenden Beschreibungen sollen kurz und prägnant erfolgen (Stichworte, kurze Sätze) a) Nennen Sie drei Gründe warum man Software in Module gliedert? (3 Punkte) b) Nennen und beschreiben Sie zwei Schritte, die eine in der Programmiersprache C geschriebene Anwendung (bestehend aus mehreren Modulen) in ein ausführbares Programm überführen? (3 Punkte) Aufgabe 4: Speicher (14 Punkte) Die folgenden Beschreibungen sollen kurz und prägnant erfolgen (Stichworte, kurze Sätze) a) Das folgende Programm wird auf einem 8-Bit AVR/Atmega32 Mikrocontroller ausgeführt. Ergänzen Sie in der untenstehenden Tabelle die Eigenschaften der genannten Variablen und Ausdrücke. (8 Punkte) volatile uint16_t a; char *b = (char *)0x1234; const char c = m ; static uint16_t d = 0; static uint8_t next() { static uint8_t s = 3; return s++; } void main(void){ char *p = malloc(132); uint8_t x = next(); b = &c; } while(1){ // wait forever } Variable Sichtbarkeit Lebensdauer Speichersegment Speicherbedarf in Bytes a Programm.bss b Programm Programm c Programm.rodata 1 d Programm 2 s.data 1 p Block Block *p (deref.) --- malloc --> free x 1-15 von 18 - - 16 von 18 -

b) Warum sollte man die Sichtbarkeit und Lebensdauer von Variablen so weit wie möglich einschränken? () Aufgabe 5: Prozesse und Signale (7 Punkte) Die folgenden Beschreibungen sollen kurz und prägnant erfolgen (Stichworte, kurze Sätze) a) Was versteht man unter einem Prozess in einem Betriebssystem? () c) Wann bietet sich die dynamische Speicherallokation mit malloc an? Welche Nachteile sind mit dynamischer Speicherverwaltung verbunden? (4 Punkte) b) Die Verwendung von Signalen kann in einem Linux-Prozess zu verschiedenen Nebenläufigkeitsproblemen führen. Beschreiben Sie exemplarisch zwei solcher Probleme und wie man mit ihnen umgeht, um korrekt funktionierende Software zu gewährleisten. (5 Punkte) - 17 von 18 - - 18 von 18 -