1 Theorie |
→ |
1.1 Die Programmiersprache
C |
1.1.2 Variablen, Kommentare
Standard-Datentypen
In Variablen werden Werte gespeichert. Diese Werte können
unterschiedliche Typen haben:
Datentyp |
Bedeutung |
char |
Buchstabe (8 Bit)
kann auch für 8-Bit-Zahlen verwendet werden |
wchar_t |
Breiter Buchstabe (16 oder 32 Bit, je
nach System)
- Windows: Verwendung wird empfohlen für CLI- und
GUI-Software (CLI: command line interface, Kommandozeilenprogramme;
GUI: graphical user interface, Windows-Programme), wenn
nicht-englische — genauer gesagt: nicht mit dem ANSI-Zeichensatz
darstellbare — Zeichen benötigt werden.
- andere: Verwendung nur nötig im Zusammenhang mit
GUI-Toolkits.
|
short int (short) |
16 Bit breite ganze Zahl im Bereich
-32768 bis 32767 |
unsigned short int
(unsigned short) |
16 Bit breite vorzeichenlose ganze Zahl
im Bereich 0 bis 65535 |
int |
vorzeichenbehaftete ganze Zahl |
unsigned |
vorzeichenlose ganze Zahl |
long int (long) |
vorzeichenbehaftete lange ganze Zahl |
unsigned long int
(unsigned long) |
vorzeichenlose lange ganze Zahl |
long long int
(long long) |
vorzeichenbehaftete lange ganze Zahl (ab
C99) |
unsigned long long int
(unsigned long long) |
vorzeichenlose lange ganze Zahl (ab
C99) |
float |
Gleitkommazahl mit einfacher
Genauigkeit |
double |
Gleitkommazahl mit doppelter
Genauigkeit |
long double |
Gleitkommazahl mit mindestens doppelter
Genauigkeit, optional höhere Genauigkeit (ab C99) |
Typ * |
Zeiger auf Daten vom angegebenen Typ |
Die Größe und damit auch der Wertebereich der Typen int,
unsigned, long und unsigned long variieren je nach Prozessor,
Betriebssystem und Entwicklungsumgebung.
Für int und unsigned wird eine Größe gewählt, die der Hersteller
der Entwicklungsumgebung für geeignet hält, sie variiert derzeit
(29.07.2014) zwischen 16 und 64 Bit. Für long und unsigned long
werden mindestens 32 Bit verwendet, für long long und unsigned long
long mindestens 64 Bit.
Der Datentyp float wird in der Anwendungsprogrammierung
heute kaum noch verwendet. Für Gleitkommazahlen wird üblicherweise
der Typ double benutzt.
Gültigkeitsbereich von Variablen
Variablen haben einen Gültigkeitsbereich (Scope) und können nur
innerhalb des Gültigkeitsbereiches verwendet werden. Man spricht
auch davon, dass Variablen nur innerhalb eines bestimmten
Code-Bereiches sichtbar sind.
Der Gültigkeitsbereich hängt davon ab, wo die Deklaration der
Variable erfolgt (siehe übernächster Abschnitt).
In verschiedenen Gültigkeitsbereichen können Variablen mit gleichen
Namen existieren, diese Variablen sind dann unabhängig
voneinander.
Lebensdauer von Variablen
Während ihrer Lebensdauer behält eine Variable ihren jeweiligen
Wert bei, sofern er nicht durch das Programm geändert wird. Die
Adresse einer Variable im Hauptspeicher ist während ihrer
Lebensdauer konstant.
Deklaration, Definition und Initialisierung von Variablen
In
C
müssen Variablen deklariert (vereinbart) werden, bevor sie benutzt
werden.
Durch die Deklaration erhält der Compiler die Information über
Speicherklasse und Datentyp der Variablen, es wird jedoch kein
Speicherplatz reserviert.
Jede Variable muss definiert sein.
Die Definition einer Variable bewirkt die Reservierung von
Speicherplatz. Die Definition einer Variable bewirkt gleichzeitig
auch die Deklaration.
Die Deklaration erfolgt durch Angabe von
Speicherklasse Typ Variablenname;
Die Speicherklasse ist dabei optional.
Mit der Form
Speicherklasse Typ Variablenname = Wert;
werden Variablen initialisiert, d.h. es wird gleich bei der
Definition ein Anfangswert angegeben.
Der Wert kann eine Konstante sein oder eine Verknüpfung mehrerer
Konstanten durch Operatoren.
Folgende Speicherklassen können für Variablen genutzt
werden:
Ort der Deklaration |
Speicherklasse |
Gültigkeitsbereich |
Datei-Ebene
(d.h. außerhalb aller
Blöcke und
Parameterlisten) |
keine Angabe |
Globale Variable
Es
wird eine globale Variable definiert. Alle nach der Definition
stehenden Funktionen des Modules können die Variable verwenden. In
anderen Modulen kann diese Variable als extern deklariert werden,
dann können auch Funktionen dieser Module auf die Variable
zugreifen. Die Lebensdauer der Variable ist die gesamte Laufzeit
des Programmes, eine Initialisierung findet höchstens einmal beim
Programmstart statt. |
Datei-Ebene |
static |
Modulinterne Variable
Es
wird
eine modulweite Variable definiert. Alle nach der Definition
stehenden Funktionen des Modules können die Variable verwenden. Aus
anderen Modulen heraus kann nicht auf die Variable zugegriffen
werden.
Die Lebensdauer der Variable ist die gesamte Laufzeit des
Programmes, eine Initialisierung findet höchstens einmal beim
Programmstart statt. |
Datei-Ebene |
extern |
Zugriff auf globale Variable
Diese
Deklaration ermöglicht den Zugriff auf eine globale
Variable, die in einem anderen Modul definiert ist. Die Lebensdauer
der Variable ist die gesamte Laufzeit des Programmes. |
in Funktionsblock
bzw. Block allgemein |
auto
keine Angabe |
Lokale Variable
Es
wird
eine
lokale Variable definiert, die nur innerhalb des Blocks sichtbar
und zugreifbar ist. Solche Variablen werden auch als automatische
Variablen bezeichnet.
Die Lebensdauer der Variable ist auf die Ausführung des Blockes
begrenzt. Wird die Funktion bzw. der Block verlassen, geht der Wert
der Variable verloren.
Bei rekursiven Aufrufen einer Funktion wird für jeden
Funktionsaufruf eine neues Variableninstanz angelegt, die
unabhängig von den Variableninstanzen vorheriger Funktionsaufrufe
ist.
Ist ein Initialisierungswert angegeben, erfolgt die Initialisierung
immer, wenn die Deklarationsanweisung bei der Ausführung des
Blockes erreicht wird. Andernfalls hat die Variable einen
unbestimmten Wert.
Nach Abarbeitung der Funktion bzw. des Blocks wird der für die
Variable benutzte Speicherplatz für andere Zwecke — z.B. Variablen
anderer Funktionsaufrufe — verwendet. |
in Funktionsblock
bzw. Block allgemein |
static |
Persistente lokale Variable
Es
wird
eine persistente lokale Variable definiert, die nur innerhalb des
Blocks sichtbar und zugreifbar ist.
Die Lebensdauer der Variable ist die gesamte Laufzeit des
Programmes, eine Initialisierung findet höchstens einmal beim
Programmstart statt. Wird die Funktion bzw. der Block verlassen,
geht der Wert der Variablen nicht verloren sondern steht wieder zur
Verfügung, wenn die Funktion bzw. der Block erneut abgearbeitet
werden. |
in Funktionsblock
bzw. Block allgemein |
extern |
Zugriff auf globale Variable
Diese Deklaration ermöglicht den Zugriff auf eine globale Variable,
die in einem anderen Modul definiert ist. |
in Funktionsblock
bzw. Block allgemein |
register |
Lokale Variable
Es
wird eine lokale Variable definiert, die nur innerhalb des Blocks
sichtbar und zugreifbar ist.
Die Lebensdauer der Variable ist auf die Ausführung des Blockes
begrenzt. Wird die Funktion bzw. der Block verlassen, geht der Wert
der Variable verloren.
Nach Abarbeitung der Funktion bzw. des Blocks wird der für die
Variable benutzte Speicherplatz für andere Zwecke — z.B. Variablen
anderer Funktionsaufrufe — verwendet.
Mit der Speicherklasse "register" wird dem Compiler vorgeschlagen,
die Variable in Speicher mit kurzer Zugriffszeit (z.B. in einem
Prozessorregister) unterzubringen. |
In Funktionen und Blöcken müssen jeweils alle
Variablendeklarationen vor der ersten Anweisung stehen.
Die Verwendung globaler oder modulweiter Variablen wird nicht
empfohlen.
Variablen-Namen
Der Variablenname (wie auch andere Identifier,
z.B. Namen von Funktionen, Datentypen, Konstanten oder Makros):
- beginnt mit Buchstaben oder
Unterstrich,
- darauf folgt optional eine Kombination aus
Buchstaben, Zahlen und Unterstrichen.
Groß- und Kleinschreibung wird unterschieden.
Ein Unterstrich am Beginn eines Namens wird nicht
empfohlen.
Die nachfolgend aufgeführten reservierten
Wörter dürfen nicht als Variablen-, Funktions- oder Datentyp-Namen
verwendet werden:
auto break case char const continue
default do double else enum extern
float for goto if inline int
long register restrict return short signed
sizeof static struct switch typedef union
unsigned void volatile while _Bool _Complex
_Imaginary
Beispielprogramm mit Variablen und Kommentaren
ex001.c
/* Testprogramm zur Quadratflaechenberechnung */
/* Copyright (C) 2014-2017 - HS Schmalkalden. All rights reserved. */
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
/** Hauptprogramm.
@return 0 bei Erfolg, alle anderen Werte bedeuten Fehler.
*/
int
main(void)
{
double slaenge; /* Seitenlaenge */
double flaeche; /* Flaeche */
printf("Bitte Seitenlaenge angeben: ");
scanf("%lg", &slaenge);
flaeche = slaenge * slaenge;
printf("Flaecheninhalt: %lg\n", flaeche);
return 0;
}
/* vim: set ai sw=4 ts=4 expandtab : */
Ab C-Standard C99 können auch //-Kommentare verwendet
werden:
...
int main(void)
{
double slaenge; // Seitenlaenge
double flaeche; // Flaeche
...
}
Variablen müssen vor Verwendung deklariert werden!
Die
Deklaration der Variablen befindet sich in den Zeilen 13 und 14,
also vor den in Zeile 15 beginnenden Anweisungen.
Bei einem Schreibfehler in den Anweisungen — z.B. "slange" anstelle
von "slaenge" — weist der Compiler darauf hin, dass die Variable
"slange" nicht existiert, damit kann der Fehler gut gefunden
werden.
In anderen Programmiersprachen ohne Zwang zur Variablendeklaration
würde hier eine Variable "slange" angelegt oder der Wert 0 für eine
noch nicht definierte Variable verwendet werden. Damit wäre der
Fehler sehr schwer zu finden.
Variablen muss ein Wert zugewiesen werden, bevor der
Wert der Variablen abgefragt bzw. verwendet wird!
Die Variable slaenge wird beispielsweise in Zeile 17
gesetzt, bevor ihr Wert in Zeile 18 in der Berechnung benutzt wird.
Die Variable flaeche wird in Zeile 18 gesetzt, bevor ihr
Wert in Zeile 19 ausgegeben wird.
Beispiele für literale Wertangaben
Als Literale werden Wertangaben bezeichnet,
bei denen der Wert direkt im C-Quelltext steht.
char-Literale
Zeichen-Darstellung |
'a' 'b' 'C' |
Hexadezimale Darstellung |
0x00 0x20 0x35 |
#include <stdio.h>
int main(void)
{
char x; /* Variable fuer Buchstaben vereinbaren */
x = 'a'; /* Wertzuweisung */
x = 0x61; /* der gleiche Effekt, hier mit Hexadezimalwert */
printf("x hat den Inhalt %c\n", x);
return 0;
}
String-Literale
Strings (Zeichenketten) werden in doppelte Anführungszeichen
gesetzt.
String-Literale sind immer "const" (konstant), d.h. sie können
nicht geändert werden.
In String-Literalen dürfen nur die Zeichen des
ASCII-Zeichensatzes verwendet werden. Andere Zeichen müssen als
Backslash-Escape-Sequenz bzw. mit ihrem Oktalwert \ooo
eingegeben werden.
#include <stdio.h>
const char x[] = { "Test" };
int main(void)
{
printf("x hat den Inhalt %s\n", x);
return 0;
}
Backslash-Sequenzen für nicht darstellbare Zeichen in char- und
String-Literalen
\n |
Zeilenvorschub
Wechsel in eine neue Zeile. |
\r |
Wagenrücklauf
Aus historischen Gründen verwenden manche Betriebssysteme — wie
z.B. Windows — am Zeilenende eine Kombination von Wagenrücklauf und
Zeilenvorschub. Die Auftrennung in Wagenrücklauf und Zeilenvorschub
geht zurück auf elektrische Schreibmaschinen und Fernschreiber, die
hierfür zwei verschiedene Tasten hatten. |
\t |
Tabulator
Wird ein Tabulator in die Standardausgabe ausgegeben, wird
mindestens eine Leerstelle gelassen, danach werden weitere
Leerstellen hinzugefügt, bis die Position ohne Rest durch 8 teilbar
ist.
Werden Text-Dateien mit Tabulatoren in einem Editor — z.B. MS
Visual Studio — bearbeitet, kann eine Tabulatorbreite eingestellt
werden. Häufig werden hier die Werte 4 oder 8 verwendet. |
\v |
Vertikal-Tabulator |
\f |
Form feed (Seitenvorschub). |
\a |
Alarm
Ausgabe eines Signaltones. |
\b |
Backspace
Löschen des letzten ausgegebenen Zeichens |
\ooo |
Angabe eines Bytes als dreistelliger
Oktalwert, z.B. \170 für 1*64+7*8+0*1. |
\\ |
Einzelner Backslash
Da ein Backslash eine Backslash-Sequenz einleitet, muss ein
einzelner Backslash durch eine Backslash-Sequenz dargestellt
werden. |
\' |
Einfaches Anführungszeichen (wenn es in
char-Literal verwendet wird). |
\" |
Doppeltes Anführungszeichen (wenn es in
String-Literal benutzt wird). |
wchar_t-Literale
Zeichen-Darstellung |
L'a' L'b' L'C'
Vorangestelltes L macht Datentyp wchar_t kenntlich. |
String-Darstellung |
L"Im Sommer sind es bis zu
35\u00B0C."
Vorangestelltes L macht Datentyp wchar_t kenntlich.
UNICODE-Zeichen oberhalb von 0xFF werden in der Schreibweise
\uXXXX dargestellt. Dabei ist XXXX ein vierstelliger
Hexadezimalwert.
Im Beispiel wird das Unicode-Zeichen U+00B0 (Grad-Zeichen,
hochgestellter Kreis) benutzt.
Zeichen oberhalb von 0xFFFF werden in der Schreibweise
\UXXXXXXXX dargestellt, XXXXXXXX ist ein
achtstelliger Hexadezimalwert. |
Hexadezimale Darstellung |
0x00 0x20 0x35 0x00B0
Je nach Bitbreite des wchar_t-Types (16 oder 32 Bit) bis zu 4 bzw.
8 Hexadezimalstellen |
int-Literale
Dezimale Darstellung |
1 2 3 -5 |
Oktale Darstellung (Basis 8, führende
0) |
0755 0233 |
Hexadezimale Darstellung (Basis 16,
führendes 0x) |
0x23F8 0x7FFF |
#include <stdio.h>
int main(void)
{
int i; /* Variablendeklaration */
i = 1; /* Wertzuweisung */
printf("In der Klausur ist die beste Note %d\n", i);
return 0;
}
unsigned-Literale (kein Vorzeichen, nachgestelltes U)
Dezimale Darstellung |
1U 2U 3U |
Oktale Darstellung |
0755U 0233U |
Hexadezimale Darstellung |
0x23F8U 0xFFFFU |
#include <stdio.h>
int main(void)
{
unsigned studenten; /* Variablendeklaration */
studenten = 15U; /* Wertzuweisung */
printf("Zur Exkursion fahren %u Studenten.\n", studenten);
return 0;
}
long-Literale (nachgestelltes L)
Dezimale Darstellung |
1L 2L 3L -5L -2147483647L |
Oktale Darstellung |
0755L 0233L |
Hexadezimale Darstellung |
0x23F8L 0x7FFFL |
unsigned-long-Literale (nachgestelltes UL)
Dezimale Darstellung |
1UL 2UL 3UL 2147483647UL |
Oktale Darstellung |
0755UL 0233UL |
Hexadezimale Darstellung |
0x23F8UL 0xFFFFFFFFUL |
#include <stdio.h>
int main(void)
{
unsigned long wunsch_konto_stand;
wunsch_konto_stand = 1000000UL;
printf("Auf dem Konto haette ich gern %lu Euro.\n", wunsch_konto_stand);
return 0;
}
double-Literale
Für Gleitkommazahlen wird die wissenschaftliche Schreibweise
(scientific notation), manchmal auch Exponentialschreibweise
(exponential notation) genannt, verwendet.
Der Wert -1,2⋅10-34 wird dabei als "-1.2e-34"
dargestellt.
Anstelle eines Komma wird ein Punkt verwendet, wie im
amerikanischen Englisch üblich. Der ganzzahlige Exponent zur Basis
10 wird durch ein "e" abgetrennt und kann positiv oder negativ
sein. Der Exponent wird nur geschrieben, falls er auch gebraucht
wird.
Vereinfacht gesagt entspricht der Buchstabe e der EXP-Taste auf
einem Taschenrechner.
Angaben ohne Exponent wie "50.345" oder "0.000387" sind auch
möglich.
#include <stdio.h>
int main(void)
{
double erd_masse; /* Masse der Erde in kg */
erd_masse = 5.9722e24;
printf("Die Masse der Erde betraegt %lg kg.\n", erd_masse);
return 0;
}
float-Literale
Float-Literale werden geschrieben wie double-Literale, durch ein
nachgestelltes "F" wird kenntlich gemacht, dass es sich um einen
float-Wert handelt, z.B. "-1.2e-34F", "50.345F" oder
"0.000387F"...
Coding Standards
Quelle: CERT C Coding
Standard 〈1〉
- Gut unterscheidbare Namen
Variablennamen (auch sonstige Identifier wie Funktionsnamen und Namen
von Datentypen, Konstanten und Makros) müssen beim Lesen optisch
gut unterscheidbar sein und sich an mindestens einer Stelle durch
ein Zeichen unterscheiden, das nicht zu einer der nachfolgenden
schlecht unterscheidbaren Kombinationen gehört:
- 0 (Zahl 0), O (großes o), D (großes D)
- 1 (Zahl 1), I (großes i), l (kleines L)
- 2 (Zahl 2), Z (großes z)
- 5 (Zahl 5), S (großes s)
- 8 (Zahl 8), B (großes b)
- n (kleines n), h (kleines H)
- rn (kleines RN), m (kleines M)
- Nur eine Variablendeklaration pro Zeile
Obwohl im Beispiel auch
double slaenge, flaeche;
möglich wäre, wird jede Variable auf einer Zeile für sich
deklariert, dabei wird der Typ jeweils mit geschrieben (also keine
Komma-getrennte Liste).
- Für long-Literale wird ein L nachgestellt, nicht l
Das l wäre mit einer 1 zu verwechseln.
- Am Anfang von Dezimal-Werten darf keine 0 stehen
Eine führende 0 führt zur Behandlung als Oktalwert.
- Minimalen Sichtbarkeitsbereich für Variablen
verwenden
Wir könnten die Variablen slaenge und sflache des
Beispielprogrammes auch außerhalb der main()-Funktion
deklarieren, z.B.
#include <stdio.h>
double slaenge; /* Seitenlaenge */
double flaeche; /* Flaeche */
int main(void)
{
printf("Bitte Seitenlaenge angeben: ");
scanf("%lg", &slaenge);
flaeche = slaenge * slaenge;
printf("Flaecheninhalt: %lg\n", flaeche);
return 0;
}
Wir tun dies aber nicht. Da die Variablen ausschließlich in der
main()-Funktion benutzt werden, gehört die Deklaration in
die Funktion.
- Eindeutige Namen (Identifier), nicht zu lang
Nach dem Standard sind nur die ersten 31 Zeichen am Namensanfang
für externe Identifier (Variablen- und Funktionsnamen) signifikant.
Für interne Identifier und Makro-Namen die ersten 64 Zeichen.
Einige C-Compiler verwenden zwar mehr signifikante Zeichen in
Namen, aber nicht alle.
Quelle: GNU
Coding Standards 〈2〉
- Aussagekräftige Variablennamen, Kleinschreibung
Variablennamen sollten möglichst selbsterklärend und lesbar sein,
z.B. ist "output_file" besser als "of".
In Variablennamen sollten nur Kleinbuchstaben und zur
Wortabgrenzung der Unterstrich vorkommen. Großbuchstaben werden nur
in Makros und enum-Konstanten verwendet (mehr dazu später).
Empfehlungen
- Variablen initialisieren
Variablen sollten initialisiert werden.
- Kommentare an Variablen
Kommentare an Variablen sollten angeben, zu welchem Zweck die
jeweilige Variable benutzt wird. Falls bereits aus dem
Variablennamen der Verwendungszweck hervorgeht, ist ein
zusätzlicher Kommentar nicht unbedingt erforderlich.
- Keine Überdeckung von Identifiern
Namen für Variablen und Funktionen sollten so gewählt werden, dass
bereits vorhandene Variablen und Funktionen (z.B. "printf",
"errno"...) nicht überdeckt werden.
In strukturierten Programmen sollte auch keine Überdeckung von
Variablen in äußeren Blöcken durch Variablendefinitionen in inneren
Blöcken vorkommen.
- Mindestlänge und suchbare Namen
Variablennamen sollten mindestens zwei Zeichen lang sein (außer
Zählschleifenvariablen in sehr kurzen Schleifen).
Häufig in C-Quelltexten vorkommende Buchstabenkombinationen sollten
Sie vermeiden. Haben Sie beispielsweise eine Variable "nt" genannt
und suchen Sie im Texteditor nach "nt", werden auch alle "nt" in
"printf" mit gefunden.
- Keine globalen Variablen
Globale Variablen sollten nur in Ausnahmefällen verwendet
werden.
Aufgaben
- Beispiel nachvollziehen
Legen Sie ein neues Projekt ex001 an, fügen Sie dem Projekt die
Datei ex001.c hinzu (siehe oben) und probieren Sie das Programm
aus.
- Übungsaufgabe
Bearbeiten Sie die Übungsaufgabe Übung 1 →
Variablen, Werte.
Externe Links
1 |
http://www.securecoding.cert.org |
2 |
http://www.gnu.org/prep/standards/standards.html |