Grundlagen der Programmiersprache C
Größen von Ganzzahltypen und Ganzzahltypen fester Breite, Integer-Promotion und Umwandlungen zwischen vorzeichenbehafteten und vorzeichenlosen Werten, Operatorpriorität, Bitoperationen, switch-Anweisungen, Wertübergabe und Zeiger, static-Variablen, Arrays und Zeigerarithmetik, Zeichenketten und sizeof, const, Funktionszeiger, malloc, free und Speicherlecks, Dangling Pointer, Pufferüberläufe, Padding in Strukturen, Unions und Endianness, Bitfelder, Makros und bedingte Kompilierung, volatile sowie undefiniertes Verhalten, erarbeitet mit Multiple-Choice-Fragen, die kurzen Code nachverfolgen.
Grundlagen der Programmiersprache C: Kernpunkte
C wird bis heute breit für hardwarenahe Software wie Betriebssysteme, Gerätetreiber und Firmware von Mikrocontrollern eingesetzt. Man kann Speicheradressen direkt handhaben und schnellen Code schreiben, doch es gibt viele Regeln, deren Fehler man ohne Kenntnis kaum bemerkt: Die Größe von int unterscheidet sich zwischen Implementierungen, Typen ändern sich mitten in einer Berechnung, und nichts hält ein Programm auf, das über das Ende eines Arrays hinaus schreibt.
Im Mittelpunkt stehen Fragen, die die Ausgabe kurzer Codestücke bei der tatsächlichen Ausführung nachverfolgen. Behandelt werden die Größen von Ganzzahltypen und die Ganzzahltypen fester Breite aus stdint.h, die Ganzzahldivision, Integer-Promotion und Vergleiche zwischen vorzeichenbehafteten und vorzeichenlosen Werten, Operatorpriorität, Bitoperationen, die Kurzschlussauswertung, Fall-through in switch-Anweisungen, Wertübergabe und die Übergabe von Zeigern, static-Variablen und Lebensdauer, Zeigerarithmetik und Arrays, die Anordnung zweidimensionaler Arrays, Zeichenketten mit strlen und sizeof, die Stellung von const und Funktionszeiger. Danach geht es um malloc und free, Speicherlecks, Dangling Pointer, Pufferüberläufe, NULL-Zeiger, Padding in Strukturen, Unions und Endianness, Bitfelder, Makros und Include-Guards, bedingte Kompilierung, volatile in Embedded-Code sowie undefiniertes Verhalten und Compiler-Optimierung. Die Programmausgaben wurden durch tatsächliches Kompilieren mit gcc unter Linux auf x86-64 überprüft. Das Nachverfolgen von Pseudocode behandelt „Grundlagen der Programmierung (Pseudocode nachverfolgen)“, Interrupts und Registerzugriffe mit volatile „Embedded Systems und Firmware“, Compiler-Optimierungen im Detail „Compiler“ und Speicheranordnung und Linken „Linker, Loader und ausführbare Formate“.
Alle Fragen zu Grundlagen der Programmiersprache C (40)
- Was legt der C-Standard über die Größe des Typs int fest?
- In Embedded-Programmen wird eine Variable für den Wert eines 32-Bit-Peripherieregisters oft nicht als unsigned int, sondern als uint32_t aus stdint.h deklariert. Was ist der Hauptgrund dafür?
- Welche Ausgabe erzeugt der obige Code mit einer Division zweier Ganzzahlen bei der Ausführung?
- Welche Ausgabe erzeugt der obige Code mit Präfix- und Postfix-++ bei der Ausführung?
- Welche Ausgabe erzeugt der obige Code, in dessen if-Bedingung = steht, bei der Ausführung?
- Der obige Code soll prüfen, ob Bit 2 des Registerwerts reg gleich 1 ist. Was ergibt die Ausführung?
- uint8_t ist ein vorzeichenloser 8-Bit-Ganzzahltyp. Welche Ausgabe erzeugt der obige Code bei der Ausführung?
- uint8_t ist ein vorzeichenloser 8-Bit-Ganzzahltyp. Welche Ausgabe erzeugt der obige Code, der x zehnmal erhöht, bei der Ausführung?
- unsigned char habe 8 Bit und int 32 Bit. Welche Ausgabe erzeugt der obige Code bei der Ausführung?
- uint8_t sei ein vorzeichenloser 8-Bit-Ganzzahltyp und int habe 32 Bit. Was ergibt die Ausführung des obigen Codes?
- int und unsigned int haben 32 Bit. Was ergibt die Ausführung des obigen Codes?
- unsigned int habe 32 Bit. Wie verhält sich der obige Code bei der Ausführung?
- Ein Programm, das c aus „char c = 200;“ mit %d von printf ausgibt, zeigt nach dem Kompilieren mit gcc für Linux auf x86-64 den Wert −56, mit gcc für Linux auf Arm dagegen 200. Was ist der Grund für den Unterschied?
- Welche Ausgabe erzeugt der obige Code, in dem b++ rechts von && und || steht, bei der Ausführung?
- Welche Ausgabe erzeugt die obige switch-Anweisung, die ein case ohne break enthält, bei der Ausführung?
- Welche Ausgabe erzeugt das obige Programm bei der Ausführung?
- Die obige Funktion f wird dreimal hintereinander aufgerufen. Welcher Rückgabewert ergibt sich beim dritten Aufruf?
- Welche Kombination gibt in C die Zeitspanne (Lebensdauer) richtig an, in der (1) eine in einer Funktion ohne static deklarierte lokale Variable, (2) ein mit malloc reservierter Bereich und (3) eine außerhalb von Funktionen deklarierte Variable existieren?
- int habe 32 Bit (Maximalwert 2147483647). Was ist das größte n, für das die obige Funktion fact(n) die Fakultät von n ohne Überlauf korrekt zurückgibt?
- int habe 4 Byte und ein Zeiger 8 Byte. Ein Zeiger p auf int hat den Wert (die Adresse) 0x1000. Welchen Wert hat p + 3?
- int habe 4 Byte und ein Zeiger 8 Byte. Welche Ausgabe erzeugt das obige Programm bei der Ausführung?
- int habe 4 Byte. Welche Ausgabe erzeugt der obige Code bei der Ausführung?
- Welche Ausgabe erzeugt der obige Code mit einem char-Array, das eine Zeichenkette enthält, bei der Ausführung?
- Nach den obigen Deklarationen wird eine der Anweisungen A „p = t;“, B „*p = 'x';“, C „q = t;“ oder D „*q = 'x';“ geschrieben. Welche Kombination führt zu Kompilierfehlern?
- Welche Ausgabe erzeugt das obige Programm mit einem Array von Funktionszeigern bei der Ausführung?
- fill und use seien separat definierte Funktionen. Welches Problem hat die obige Funktion?
- Was trifft auf den Zeiger zu, den die obige Funktion make zurückgibt?
- Warum wird in C empfohlen, unmittelbar nach free(p); die Anweisung p = NULL; zu schreiben?
- Der obigen Funktion save wird die Zeichenkette "ABCDEFGH" mit 8 Zeichen übergeben. Was passiert?
- Was trifft in C auf die Dereferenzierung eines NULL-Zeigers zu (wenn *p gelesen wird, während p NULL ist)?
- char habe 1 Byte und int 4 Byte, und int werde wie in üblichen Umgebungen an Adressen ausgerichtet, die ein Vielfaches von 4 sind. Welche Ausgabe erzeugt der obige Code bei der Ausführung?
- uint32_t sei ein vorzeichenloser 32-Bit- und uint8_t ein vorzeichenloser 8-Bit-Ganzzahltyp, und die Umgebung sei Little-Endian. Welche Ausgabe erzeugt der obige Code bei der Ausführung?
- Welche Ausgabe erzeugt der obige Code, der 9 in ein 3-Bit-Bitfeld schreibt, bei der Ausführung?
- Welche Ausgabe erzeugt der obige Code, der das mit #define definierte Makro SQUARE verwendet, bei der Ausführung?
- Die Header-Datei sensor.h wurde wie oben geschrieben. Welchen Zweck haben die drei Zeilen #ifndef, #define und #endif?
- Der obige Code steht in der Funktion main. Welche Ausgabe erzeugt er bei der Ausführung?
- Bei einem Mikrocontroller wird das Ausgaberegister wie oben deklariert und verwendet. Welche Aussage über diese Deklaration ist richtig?
- Welche Aussage beschreibt das undefinierte Verhalten im Sinne des C-Standards richtig?
- int und unsigned int haben 32 Bit. Was davon ist nach dem C-Standard undefiniertes Verhalten?
- Wird die obige Funktion mit gcc und aktivierter Optimierung kompiliert, kann die Prüfung if (p == NULL) entfernt werden. Was ist der Grund dafür?
Weitere Themen in Computersysteme
- Computerarithmetik IEEE 754, Festkomma, Rundungsfehler
- Wahrscheinlichkeitsrechnung, Statistik und Warteschlangen Abzählen, Verteilungen, Schätzen und Testen, M/M/1
- Befehlssatz und Assembler RISC-V, Adressierungsarten, Aufrufkonvention
- Compiler Parsing, SSA, Optimierung, Registerzuteilung
- Linker, Loader und ausführbare Formate ELF, Symbole, Relokation, dynamisches Linken
- Betriebssystem und Hardware Interrupts, Systemaufrufe, Page Faults
- Grundlagen von Linux und der Kommandozeile Shell, Zugriffsrechte, Pipes, Skripte
- Speicherhierarchie und Leistung Cache, Ersetzungsstrategie, drei Miss-Arten
- Multicore und Synchronisation MESI, atomare Befehle, Memory Barriers
- GPU-Programmierung Warps, Shared Memory, Coalescing, Occupancy
- KI-Hardware und Software-Stack Inferenz vs. Training, Quantisierung, Roofline
- Grundlagen des maschinellen Lernens Lernverfahren, Bewertungskennzahlen, neuronale Netze
- Embedded Systems und Firmware GPIO, UART/SPI/I2C, RTOS
- Hardwarebeschreibungssprachen und Verifikation Verilog, Latches, Zustandsautomaten, Testbench
- Schnittstellen und Busstandards PCIe, USB, SerDes, CXL
- Grundlagen der Computernetzwerke TCP/IP, Subnetzberechnung, DNS, TLS
- Grundlagen der Webtechnologien HTTP, Cookies, REST, CORS, Caching
- Grundlagen der Funkkommunikation Modulation, OFDM, MIMO, HF-Schaltungen
- Grundlagen der Informationssicherheit Kryptografie, Authentifizierung, Webangriffe
- Grundlagen der Datenbanken SQL, Normalisierung, Transaktionen
- Datenstrukturen und Algorithmen Komplexität, Suche, Sortieren, Graphen
- Grundlagen der Programmierung (Pseudocode nachverfolgen) Pseudocode, Tracing, Arrays, Rekursion
- Softwareentwicklung und Projektmanagement Prozesse, Tests, Termin- und Kostensteuerung
- Grundlagen von Unternehmensstrategie und Rechnungswesen Rechnungswesen, Break-even, Strategie, Marketing
- IT-Service-Management und IT-Audit SLAs, Incidents und Probleme, Audit und interne Kontrolle
- Systemarchitektur und Zuverlässigkeit Redundanz, RAID, Backups, Cloud
- Grundlagen von Cloud und Containern Docker, Kubernetes, geteilte Verantwortung, IaC
- Leistungsbewertung und Profiling Amdahlsches Gesetz, CPI, Engpässe
- Hardwaresicherheit Seitenkanäle, Secure Boot, TEE, PUF
- Energieverwaltung (softwaregesteuert) DVFS, Power Gating, Schlafzustände