int, float, âŠint x, int y;struct kennzeichnet eigene Datentypen, gefolgt von TypbezeichnerMember-Deklaration innerhalb eines Codeblocks {}
Deklaration wird per Semikolon terminiert
fĂŒr Member und Datenstruktur
Zugriff auf einzelnen Member mit Punktoperator(.)
{}) umfasst (wie Array-Initialisierung)struct Adresse addr = { 44227, "Dortmund", "Otto-Hahn-StraĂe 14" };0 initialisiert00 initialisiert#include <stdio.h>
struct Adresse {
unsigned int plz;
char ort[30];
char strasse[30];
};
int main() {
struct Adresse addr = {
.ort = "Dortmund",
.strasse = "OH 14", };
printf("Adresse: %d %s, %s\n",
addr.plz, addr.ort,
addr.strasse);
return 0;
}
typedefFĂŒhrt einen neuen Namen (Alias) fĂŒr bestehenden Datentyp ein
HĂ€ufiger Anwendungszweck: Vereinfachen langer oder komplizierter Typen
Funktionsweise Àhnlich wie #define, aber nicht Teil des PrÀprozessors
â Teil des Compilers (und auf Typen beschrĂ€nkt)
Beispiel:
(Auszug aus den Quelldateien des Clang-Compilers)
typedef#include <stdio.h>
#include <stdint.h>
struct Int{ uint32_t value; };
typedef struct Int Int;
typedef struct { uint32_t value; } Int2;
int main () {
// Kein 'struct' nötig
Int i = { 3 };
Int2 i2 = { 2 };
printf("%d, %d\n", i.value, i2.value);
return 0;
}
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
int main() {
struct { // Anonyme Deklaration
bool enabled;
uint8_t value;
} cfg = { true, 33 }; // Init
printf("Intensity: %d\n", cfg.value);
return 0;
}
â FĂŒr hĂ€ufiger eingesetzte Strukturen lohnt sich separate Deklaration als Tagged Struct
unionstruct#include <stdint.h>
#include <stdio.h>
union IntChar {
uint32_t value;
uint8_t arr[4];
};
int main() {
union IntChar u1 = { 65 }; // 'A'
printf("%c\n", u1.arr[0]);
printf("%d\n", u1.value);
u1.arr[3] = 55;
printf("%c\n", u1.arr[0]);
printf("%d\n", u1.value);
return 0;
}
#include <stdint.h>
union IntChar {
uint32_t value;
uint8_t arr[4];
};
int main() {
IntChar u1 = { 15 }; // Ok
IntChar u2 = { .arr = {'a','b','c','d'}}; // Ok
// IntChar u3 = { {'a','b','c','d'} }; // Error
return 0;
}
Bisher: Datenstrukturelemente belegen ganze Bytes
Jetzt: EinschrÀnkung auf einzelne Bits
Sogenannte Bitfelder (Bit-fields) belegen nur \(N\) Bits
Notation ist simpel: Bitbreite folgt auf Elementdeklaration
â Typ Bezeichner: Breite
#include <stdint.h>
struct Byte {
uint8_t lower_half: 4;
uint8_t upper_half: 4;
};
int main() {
struct Byte b { 0x7, 0xF};
b.lower_half = 1;
}
#include <stdint.h>
#include <stdio.h>
struct Byte {
uint8_t lower_half: 4;
uint8_t upper_half: 4;
};
int main() {
struct Byte b = { 0x47, 0x11};
printf("Lower: %d, Upper: %d\n",
b.lower_half, b.upper_half);
return 0;
}
__attribute__((packed))
#pragma pack()#include <stdint.h>
#include <stdio.h>
#define MIC_CFG_REGISTER 0x4711
void write_register (size_t address, uint16_t value) { }
union {
uint16_t value;
struct {
uint16_t enabled :1; // Bit 0
uint16_t sensitivity :6; // Bit 1-6
uint16_t gain :6; // Bit 7-12
uint16_t :3; // Leer, reserviert
} __attribute__((packed));
} mic_cfg;
int main() {
mic_cfg.value = 0; // Alles nullen (Init)
mic_cfg.sensitivity = 0x20;
mic_cfg.gain = 0x03;
printf("Sensitivity: %#x, Gain: %#x\n",
mic_cfg.sensitivity, mic_cfg.gain);
write_register(MIC_CFG_REGISTER, mic_cfg.value);
printf("Value: %#x\n", mic_cfg.value);
return 0;
}
Neben Strukturen und Unions weiteren selbstdefinierbaren Datentyp:
AufzÀhlungen (Enumerations)
SchlĂŒsselwort enum
Hauptverwendungszweck: BĂŒndelung von ZustĂ€nden bzw. konstanten Werten
Besser geeignet als #define
enum-Typen sind intern standardmĂ€Ăig vom Typ int0:#include <stdio.h>
enum Animal {HUND, KATZE, MAUS};
int main() {
enum Animal a = KATZE;
a = a + 1;
printf("Animal: %d\n", a);
return 0;
}
C++ versucht, diese SchwÀche zu umgehen
EinfĂŒhrung von neuem Typ enum struct bzw. enum class
Intern immer noch int, aber keine implizite Umwandlung mehr möglich
(Compiler verhindert dies)
struct, union, enumâ Hier nur die Grundlagen
đš Achtung: Speicherallokation eine der gröĂten StĂ€rken, gleichzeitig gröĂte SchwĂ€che
malloc()
free() erforderlichmalloc() als auch free() Teil von stdlib.h#include <stdlib.h>
int main() {
void * memory = malloc(4); // 4 Bytes angelegt
free(memory); // Freigabe
return 0;
}
void * bezeichnet typischerweise nicht genauer definierten Speicher
malloc()* bedeutet, dass auf den Beginn eines Speicherblocks gezeigt wird (wie Index 0 eines Arrays)void *sizeof() gibt GröĂe des angegebenen Objekts in Bytes zurĂŒck
sizeof(char); // == 1malloc() noch weitere Allokationsfunktionen verfĂŒgbarcalloc():
malloc() nötig0 initialisiertrealloc():
â Reihe von Speicheroperationen in string.h
memcpy, memcmp,memmove, memset
unsigned char interpretiertmemcpy: Kopiert size Bytes von Speicher src nach dest
memcpy(dest, src, size);memmove: Verschiebt size Bytes von Speicher src nach dest
memmove(dest, src, size);memcmp: Vergleicht die ersten size Bytes von Speicher src mit dest
memcmp(dest, src, size);memset: Kopiert das Zeichen c in die ersten size Bytes dest Speichers dest
memset(dest, ch, size);#include <stdlib.h>
int main() {
{
void * memory = malloc(4);
/* Viele Zeilen Code */
// free(memory); wurde vergessen
} // memory ab hier nicht mehr benutzbar
return 0;
}
free() kann sehr leicht vergessen werden, besonders bei langen FunktionenWenn möglich, fĂŒr jedes malloc() direkt free()-Statement schreiben
malloc()#include <stdlib.h>
#include <stdio.h>
int main() {
while (true) {
void * memory = malloc(1024 * 1024); // 1 KiByte
if (memory == nullptr) {
break;
}
}
printf("Speicher voll!\n");
return 0;
}
struct: Verbund von Datentypenunion: Vereinigung von Datentypenenum: AufzÀhlung