Your Browser is not longer supported

Please use Google Chrome, Mozilla Firefox or Microsoft Edge to view the page correctly
Loading...

{{viewport.spaceProperty.prod}}

Implementierungsabhängiges Verhalten gemäß dem ANSI-/ISO-C-Standard

&pagelevel(3)&pagelevel

Bezeichner

Grundsätzlich können Namen in beliebiger Länge gebildet werden. Bei internen Namen sind alle Zeichen signifikant. Bei externen Namen wertet der Compiler standardmäßig maximal 32 Zeichen aus (siehe Regeln unten). Folgende Zeichen sind zur Bildung von Namen zulässig: Gemäß ANSI-/ISO-C die Ziffern 0 bis 9, die Großbuchstaben A bis Z, die Kleinbuchstaben a bis z und der Unterstrich _. Als Erweiterung gegenüber ANSI-/ISO-C sind standardmäßig auch das Dollarzeichen $ und das at-Zeichen @ in Namen zugelassen. Dies lässt sich mit entsprechenden Optionen ausschalten (-K no_dollar, -K no_at bzw. DOLLAR-ALLOWED=*NO, AT-ALLOWED=*NO).
Multibyte-Zeichen in Bezeichnern werden nicht unterstützt. Im Modus C11 können aber universal-character-names genutzt werden. Diese haben die Form \u0123 oder \U01234567. Nicht alle Ziffernfolgen sind erlaubt.

Für externe Namen gilt Folgendes:

  • Standardmäßig, d.h. die Optionen -K c_names_std bzw. C-NAMES=*STD sind gesetzt, können externe Namen maximal 32 Zeichen lang sein. Längere Namen werden vom Compiler auf 32 Stellen verkürzt.
    Bei der Generierung von gemeinsam benutzbarem Code (Optionen -K share bzw. SHAREABLE-CODE=*YES) können nur maximal 30 Zeichen genutzt werden.

    Bei Angabe der Optionen -K c_names_unlimited bzw. C-NAMES=*UNLIMITED findet keine Namensverkürzung statt. Der Compiler generiert Entry-Namen im EEN-Format. EEN-Namen können eine Länge von maximal 32000 Zeichen erreichen.

  • Standardmäßig werden Kleinbuchstaben in Großbuchstaben und Unterstriche (_) in Dollarzeichen ($) übersetzt.
    Durch die Angabe entsprechender Optionen (-K llm_case_lower, -K llm_keep bzw. LOWER-CASE-NAMES=*YES, SPECIAL-CHARACTERS=*KEEP) können Kleinbuchstaben und Unterstriche in den externen Namen beibehalten werden.

  • Externe Namen dürfen nicht mit „I“ beginnen.

  • Enthält der Identifier universal-character-names, so werden diese als Zeichensequenz im externen Namen abgebildet. Dabei wird der Gegenschrägstrich durch ein Minus-Zeichen ersetzt. Der Buchstabe u bzw. U und die Ziffern bleiben erhalten.

Die obigen Regeln gelten auch für externe Namen, die in C++ als extern "C" deklariert sind und außerdem für Static-Funktionen.

main-Funktion

Der Compiler lässt für die Funktion main die Return-Typen int und void zu. Der Return-Typ void führt immer zu einer Compiler-Meldung (meist eine Warnung).

Um einem Programm beim Aufruf Argumente übergeben zu können, sind für die Funktion main zwei formale Parameter vorzusehen:

int main(int argc, char *argv[])

Der erste Parameter argc zeigt die Anzahl der übergebenen Argumente an. Da das erste Argument argv[0] gemäß Konvention der Programmname ist, ist die Argumentanzahl mindestens 1.

Der zweite Parameter argv ist ein Zeiger auf einen Vektor von Zeichenketten. In ihm werden der Programmname (in argv[0]) und alle beim Programmaufruf eingegebenen Argumente als mit dem Nullbyte (\0) abgeschlossene Zeichenketten abgespeichert.

Als Erweiterung gegenüber ANSI-/ISO-C kann für die Funktion main ein dritter Parameter char *envp[] vereinbart werden (siehe "Erweiterungen gegenüber ANSI-/ISO-C").

Weitere Einzelheiten zur Übergabe von Parametern an die main-Funktionen finden Sie im Abschnitt „Eingabe der Parameter für die main-Funktion“.

Zeichen (character)

Der Datentyp char wird von diesem Compiler standardmäßig als unsigned behandelt (siehe auch Optionen -K uchar, -K schar bzw. SIGNED-CHARACTER=*NO/*YES).

Der Wert eines EBCDIC-Zeichens ist immer positiv.
Der Wert von ’\377’ (oktal) oder ’\xFF’ (sedezimal) ist also 255.
Das Verhalten ist undefiniert, wenn eine character-Konstante einen numerischen Wert enthält, der nicht im EBCDIC-Zeichensatz enthalten ist.

Der Wert einer character-Konstante, die mehr als ein Zeichen enthält (z.B. ’ab’), berechnet sich aus dem EBCDIC-Wert der Zeichen als Zahl zur Basis 256. Das erste (rechte) Zeichen wird mit 1 multipliziert, das zweite Zeichen mit 256, das dritte Zeichen mit 256 * 256, das vierte Zeichen mit 256 * 256 * 256.
Z.B. ergibt ’abcd’ den Wert ’a’ * 2563 + ’b’ * 2562 + ’c’ * 256 + ’d’ (= 2172814212).

Der Wert einer Multibyte-Zeichenkonstante in der Form L’ab’ ist in dieser Implementierung identisch mit dem Wert einer Zeichenkonstante in der Form ’ab’.

Wenn eine character-Konstante fünf oder mehr Zeichen enthält, wird ein Error ausgegeben und kein Code generiert.
Die Zuweisung eines int an char geschieht modulo 256.

Multibytezeichen

In dieser Implementierung haben Multibytezeichen immer die Länge 1 Byte und wchar_t-Werte sind immer Integer-Werte der Größe 32 bit.

Zeiger

Ein Zeiger wird in 4 Bytes dargestellt, mit Ausrichtung auf Wortgrenze. Die Differenz zwischen zwei Zeigern ist vom Typ int (ptrdiff_t).

Arrays

Arrays in C haben üblicherweise feste Grenzen, die Größe eines Arrays ist in solchen Fällen bereits zur Übersetzungszeit bekannt. Eine Ausnahme bilden die VLA (variable lenght array) aus C11. Diese können nur auf Block-Scope vorkommen.

Ein Arrayname wird in C immer wie ein Zeiger behandelt, der auf das erste Element des Arrays zeigt.

Die Elemente werden sequenziell im Speicher abgelegt, das erste Element hat den Index 0. Bei mehrdimensionalen Arrays werden die Elemente so im Speicher abgelegt, dass der letzte Index am schnellsten variiert. Jedes Element wird, wie das Array selbst, entsprechend dem Elementtyp ausgerichtet.

Strukturen

In Strukturen belegen die Komponenten Platz in der Reihenfolge ihrer Deklaration. Jede Komponente wird dabei entsprechend ihrem Typ ausgerichtet. Die Struktur selbst wird auf die maximal erforderliche Ausrichtungsgröße einer Komponente ausgerichtet. Die Strukturgröße ist ein Vielfaches dieser Ausrichtung, damit Arrays von diesen Strukturen gebildet werden können. Siehe auch „Interne Darstellung der Datentypen (Ausrichtung und Darstellung in Registern)“ und Präprozessor-Anweisung #pragma aligned, "aligned-Pragma".

Beispiel

                          Größe:       Ausrichtung:      Offset:
struct {  char  a;        1 Byte       Bytegrenze         0 (Wortgrenze)
          short b;        2 Byte       Halbwortgrenze     2
          char  c;        1 Byte       Bytegrenze         4
          long  d;        4 Byte       Wortgrenze         8
          char  e;        1 Byte       Bytegrenze        12
       };                                                16 (Strukturende)

Bitfelder

Bitfelder werden von links nach rechts in maximal 64 Bit (Doppelwort) abgespeichert.

Bitfelder können folgendermaßen definiert sein:

int        unsigned int        signed int
long       unsigned long       signed long
long long  unsigned long long  signed long long
short      unsigned short      signed short
char       unsigned char       signed char

Bitfelder ohne den Zusatz unsigned oder signed werden entsprechend dem Basis-Datentyp dargestellt, d.h. char als unsigned und int, long, long long und short als signed. Bei expliziter Angabe von signed oder unsigned werden die Bitfelder entsprechend dieser Angabe dargestellt. Dieses voreingestellte Verhalten kann durch folgende Optionen verändert werden: -K schar , -K signed_fields_unsigned und -K plain_fields_unsigned bzw. SIGNED-FIELDS=*UNSIGNED, PLAIN-FIELDS=*UNSIGNED, SIGNED-CHARACTER=*YES.

Die angegebene Anzahl von Bits wird ohne Ausrichtung angelegt, falls das Bitfeld noch ganz im aktuellen Byte, Halbwort, Wort oder Doppelwort Platz findet; andernfalls wird das Bitfeld entsprechend dem Grundtyp auf Byte-, Halbwort-, Wort- oder Doppelwortgrenze ausgerichtet (siehe Beispiel unten).

Beispiel

struct
{
    unsigned short  a : 7;
    unsigned short  b : 5;
    unsigned short  c : 5;
    unsigned short  d : 8;
} x;

Aufzählung (enum)

Ohne explizite Wertzuweisung werden den Konstanten bei der Definition eines Aufzählungstyps nacheinander die Zahlen 0, 1, etc. zugeordnet. Wird einer Konstanten ein Wert explizit zugewiesen, erhalten die nachfolgenden Konstanten automatisch einen entsprechend höheren Wert.

Standardmäßig wird ein Aufzählungstyp je nach den äußeren Grenzen (höchster und niedrigster Wert) dargestellt wie char, short oder long. Mit den Compileroptionen -K enum_long bzw. ENUM-TYPE=*LONG kann erreicht werden, dass enum-Daten unabhängig von ihrem tatsächlichen Platzbedarf stets als long dargestellt werden.

Typqualifizierer volatile

volatile verhindert die Optimierung beim Zugriff auf eine Variable. Anstelle der Verwendung des alten Inhalts wird stets neu aus dem Speicher eingelesen. Bei allen Zuweisungen, auch bei redundanten, wird der entsprechende Wert unmittelbar in den Speicher geschrieben. Es wird von der Implementierung garantiert, dass Referenzen auf volatile-Objekte auf Werte zeigen, die im Speicher stehen, im Gegensatz zu nicht-volatile-Objekten, die weitreichenden Optimierungen unterzogen und beispielsweise in Registern gehalten werden.

Im K&R-Modus wird volatile nur syntaktisch akzeptiert.

size_t

size_t entspricht in dieser Implementierung unsigned int.

ptrdiff_t

ptrdiff_t entspricht in dieser Implementierung int.

Konvertierung von Datentypen

  • Integer --> Integer

    Bei der Konvertierung eines vorzeichenlosen Integer-Werts in einen vorzeichenbehafteten Integer-Typ gleicher Größe wird das Bitmuster beibehalten. Wenn der Wert nicht aufgenommen werden kann, entspricht das Ergebnis der Subtraktion der größtmöglichen Zahl + 1 von der gegebenen Größe.

    Wenn bei der Konvertierung eines Integer-Werts in einen kleineren Integer-Typ der Wert nicht aufgenommen werden kann, wird das Bitmuster beibehalten. Die höherwertigen Bits werden abgeschnitten.

  • Gleitkommazahl --> Integer

    Bei der Konvertierung einer Gleitkommazahl nach Integer wird in Richtung 0 abgeschnitten.

    Beispiel

    (int)(-1.5) ist -1

    (int)(1.5) ist 1

    Das Ergebnis ist nicht definiert, wenn die zu konvertierende Gleitkommazahl zu groß ist, um als Integer-Wert dargestellt werden zu können.

  • Integer --> Gleitkommazahl

    Bei der Konvertierung eines Integer- in einen Gleitkomma-Typ, der den korrekten Wert nicht aufnehmen kann, wird gerundet.

  • Gleitkommazahl --> Gleitkommazahl

    Bei der Konvertierung einer Gleitkommazahl in eine kleinere Gleitkommazahl (z.B. double nach float) wird gerundet.

  • Integer <--> Zeiger

    Bei der Konvertierung Integer nach Zeiger und umgekehrt wird das Bitmuster nicht verändert (einfache Uminterpretierung).

Vorzeichen des Divisionsrestes

Der Rest einer ganzzahligen Division hat immer dasselbe Vorzeichen wie der Dividend.

Beispiel

(-5) / 2 ist -2, (-5) % 2 ist -1
5 / (-2) ist -2, 5 % (-2) ist 1

Rechts-Shift logisch und arithmetisch

Rechts-Shift ist logisch (Auffüllen von 0-Bits), wenn der linke Operand unsigned ist, sonst arithmetisch (Auffüllen von Vorzeichen-Bits).

Beispiel

(-8) >> 1 ist -4

Bitweise Operationen auf vorzeichenbehaftete Integerwerte

Bitweise Operationen (Operatoren ~, <<, &, ^, und |) werden bei Interpretation als vorzeichenlose Integer ausgeführt, das Ergebnis ist wieder vorzeichenbehaftet.

Deklaratoren

Für die Vereinbarung eines Typs sind beliebig viele Deklaratoren zugelassen.

switch-Anweisung

Pro switch-Anweisung sind beliebig viele case-Zweige zugelassen.

Präprozessor-Anweisungen

  • #include

    Eine Folge von Include-Dateien <name> bzw. "name" ist nicht zulässig. Es wird nur der erste Name akzeptiert.

    #include-Anweisungen, in denen die Namen der Include-Dateien Schrägstriche (/) für Verzeichnisse enthalten, werden vom Compiler auch im Falle von PLAM-Bibliothekselementen akzeptiert. Jeder Schrägstrich in den Namen von benutzereigenen und Standard-Include-Dateien wird intern zur Suche in PLAM-Bibliotheken in einen Punkt umgewandelt.
    In Quellprogrammen, die z.B. aus dem POSIX- oder UNIX-System portiert werden, müssen deshalb die Schrägstriche nicht in Punkte umgewandelt werden.

    Beispiel

    #include <sys/types.h>

    Der Compiler sucht die Standard-Include-Datei SYS.TYPES.H in der CRTE-Bibliothek $.SYSLIB.CRTE.

    Bezüglich der Schachtelung von Include-Dateien gibt es keine Einschränkungen.

  • #pragma

    Siehe Abschnitt „Pragmas“.

  • __DATE__, __TIME__

    Falls Datum und Uhrzeit der Übersetzung nicht verfügbar sind, sind diese Makros folgendermaßen definiert:

    __DATE__

    "Jan 1 1970"

    __TIME__

    "01:00:00"

Größe und Wertebereiche der elementaren Datentypen

Typ

Bit

Wertebereiche

char

8

0 .. 255

signed char

8

-128 .. 127

short

16

-32768 .. 32767

unsigned short

16

0 .. 65535

int

32

-2147483648 .. 2147483647 (-231 .. 231-1)

unsigned int

32

0 .. 4294967295 (0 .. 232-1)

long

32

wie int

unsigned long

32

wie unsigned int

long long

64

-9223372036854775808 .. 9223372036854775807 (-263.. 263-1)

unsigned long long

64

0 .. 18446744073709551615 (0 .. 264-1)

float

32

10-75 .. 0.79*1076

double

64

wie float

long double

124

wie float

Interne Darstellung der Datentypen (Ausrichtung und Darstellung in Registern)

Im Folgenden wird zusammenfassend gezeigt, wie die einzelnen C-Datentypen intern im Speicher abgebildet werden.

Bei skalaren Typen wird zusätzlich auf ihre Abbildung in Registern eingegangen. Dadurch wird zum einen festgelegt, wie die Variablen mit der Speicherklasse register dargestellt werden, zum anderen, wie der Wert einer solchen Variablen in Ausdrücken interpretiert wird.

Datentyp

Größe

Ausrichtung

Darstellung in Registern

char, unsigned char,
signed char

1 Byte

Bytegrenze

rechtsbündig

short, unsigned short

2 Byte

Halbwortgrenze

rechtsbündig

int, unsigned int

4 Byte

Wortgrenze

wie im Speicher

long, unsigned long

4 Byte

Wortgrenze

wie im Speicher

long long, unsigned long long

8 Byte

Doppelwortgrenze

keine Darstellung in Registern

Zeiger

4 Byte

Wortgrenze

wie im Speicher

float

4 Byte

Wortgrenze

linksbündig

double

8 Byte

Doppelwortgrenze

Für Darstellung wird keine
Konvertierung benötigt

long double

16 Byte

Doppelwortgrenze

Für Darstellung wird ein Gleit-
punkt-Registerpaar verwendet

Datentyp

Größe und Ausrichtung

Aufzählung

Je nach den Grenzwerten dargestellt wie char, short oder long
mit entsprechender Ausrichtung.

Arrays

Größe und Ausrichtung entsprechend dem Elementtyp.

Strukturen

Größe und Ausrichtung für jede einzelne Komponente nach obigen
Regeln. Gesamtausrichtung nach maximaler Ausrichtung der
Komponenten.

Bitfelder

Die angegebene Anzahl von Bits wird ohne Ausrichtung angelegt,
wenn dadurch die Ausrichtungsgrenze des Grundtyps nicht
überschritten wird, ansonsten werden die Bits gemäß der
Ausrichtung des Grundtyps angelegt.

Implementierungsspezifische Grenzwerte

Die meisten Grenzwerte werden von den Systemressourcen vorgegeben (z.B. vom virtuellen Speicher). Nur die folgenden Grenzwerte sind von der Implementierung vorgegeben:

Merkmal

Maximalwert

Anzahl der Parameter in einer Makrodefinition

224-1

Anzahl der Argumente in einem Makroaufruf

224-1

sizeof-Grenzwert

231

Speicherklassen

In diesem Abschnitt wird zusammenfassend gezeigt, wie den Variablen in Abhängigkeit von ihrer Speicherklasse Speicher zugeordnet wird.

Speicherklasse register

Variablen können mit register als Registervariablen deklariert werden. Dies ist ein Hinweis an den Compiler, dass die Variablen relativ oft benutzt werden und deshalb möglichst in Registern gehalten werden sollen. Beim Lesen und Schreiben dieser Variablen werden teure Speicherzugriffe eingespart. Die Optimierung des Compilers kann sich allerdings über diese Hinweise hinwegsetzen und nach einem eigenen Algorithmus bestimmte Variablen als Registervariablen realisieren.

Speicherklasse auto (default)

Für lokale Variablen mit der (voreingestellten) Speicherklasse auto wird Speicher in einer Automatic Data Area reserviert.

Parameter in der Parameterliste

Funktionsparameter werden in der Reihenfolge ihres Auftretens in einer Parameterliste übergeben.

Alle unsigned... Parameter werden wie unsigned dargestellt, alle anderen ganzzahligen Parameter (char, short) wie int: rechtsbündig in je einem Wort, ausgerichtet auf Wortgrenze und evtl. nach links aufgefüllt mit Vorzeichenbits (int) oder Nullen (unsigned...). Zeiger belegen ein Wort.

Abhängig vom Sprachmodus, werden Gleitkommazahlen unterschiedlich übergeben.
Im K&R-Modus werden Gleitkommazahlen (float, double) immer in doppelter Genauigkeit übergeben, also als Doppelwort ausgerichtet auf Doppelwortgrenze.
Im ANSI-Modus werden float-Werte nur dann in doppelter Genauigkeit übergeben, wenn keine Prototyp-Deklaration vorhanden ist. Im anderen Fall werden float-Werte in einfacher Genauigkeit übergeben, also als Wort ausgerichtet auf Wortgrenze.
In den C++-Sprachmodi werden float-Werte immer in einfacher Genauigkeit übergeben, da Prototyp-Deklarationen vorhanden sein müssen.

long double wird in zwei Doppelworten übergeben, ausgerichtet auf Doppelwortgrenze.

Strukturparameter werden je nach Bedarf auf Wort- oder Doppelwortgrenze ausgerichtet. Die Größe einer Struktur wird nach der maximal erforderlichen Ausrichtungsgröße einer Komponente aufgefüllt. Wenn z.B. eine Struktur nur short- und char-Komponenten enthält, ergibt sich als Größe ein Vielfaches von 2 Bytes.

Arrays können nicht als Wert übergeben werden. Es wird ein Zeiger auf das erste Array-Element übergeben.

Statische Variablen

Für die folgenden Arten von statischen Variablen reserviert der Compiler bereits bei der Übersetzung Speicher:

  • Lokale static-Variablen

  • Globale static-Variablen

  • Globale extern-Variablen

Der Unterschied zwischen diesen Speicherklassen liegt im Gültigkeitsbereich:

  • Lokale static-Variablen sind innerhalb einer Funktion mit dem Speicherklassenattribut static definierte Variablen. Sie sind nur der Funktion bekannt, in der sie definiert wurden.

  • Globale static-Variablen sind außerhalb einer Funktion mit dem Speicherklassenattribut static definierte Variablen. Diese sind nur innerhalb einer Übersetzungseinheit bekannt.

  • Globale extern-Variablen sind Variablen, die außerhalb einer Funktion ohne das Speicherklassenattribut static definiert wurden. Auf diese Variablen kann auch in anderen Übersetzungseinheiten zugegriffen werden, wenn diese dort mit dem Attribut extern deklariert werden.

Funktionen ohne Prototyp

Wenn eine Funktion ohne Prototyp aufgerufen wird und es sind Parameter-Informationen vorhanden, wird in einigen Fällen ein Fehler ausgegeben. Dies geschieht, wenn eine Definition „alten Stils“ oder ein Prototyp im K&R-Modus vorgefunden werden.

Sind Argument und Parameter – nach der üblichen Typ-Erweiterung – verschiedenen Typs und einer der folgenden Punkte trifft zu, wird ein Fehler ausgegeben:

  • Parameter und Argument sind von unterschiedlicher Größe

  • Parameter und Argument sind von unterschiedlicher Ausrichtung

  • Der Parameter ist vom Typ float, double oder long double

  • Das Argument ist vom Typ float, double oder long double

Der Fehler kann zu einer Warnung herabgestuft werden. Wird dies getan, wird der Aufruf zur Laufzeit in aller Regel scheitern.