Handbuch zur dynamischen Ablaufverfolgung in Solaris

Kapitel 2 Typen, Operatoren und Ausdrücke

Mit D können Sie auf zahlreiche Datenobjekte zugreifen und sie manipulieren: Variablen und Datenstrukturen lassen sich erstellen und ändern, im Betriebssystemkernel und in Benutzerprozessen definierte Datenobjekte können angesteuert und Integer-, Fließkomma- und Stringkonstanten deklariert werden. D bietet eine Obergruppe der ANSI-C-Operatoren, die für die Manipulation von Objekten und zum Erstellen komplexer Ausdrücke dienen. In diesem Kapitel wird der Regelsatz für Typen, Operatoren und Ausdrücke in allen Einzelheiten beschrieben.

Bezeichnernamen und Schlüsselwörter

In D bestehen Bezeichnernamen aus Groß- und Kleinbuchstaben, Ziffern und Unterstrichen. Das erste Zeichen muss ein Buchstabe oder Unterstrich sein. Alle mit einem Unterstrich (_) beginnenden Bezeichnernamen sind den D-Systembibliotheken vorbehalten. Verzichten Sie in Ihren D-Programmen auf solche Namen. Vereinbarungsgemäß verwenden D-Programmierer normalerweise Namen mit Groß- und Kleinbuchstaben für Variablen und Namen in ausschließlich Großbuchstaben für Konstanten.

Die D-Schlüsselwörter stellen spezielle, zur Verwendung in der Programmiersprachensyntax selbst reservierte Bezeichner dar. Diese Namen werden stets in Kleinbuchstaben angegeben und dürfen nicht als Namen für D-Variablen verwendet werden.

Tabelle 2–1 D-Schlüsselwörter

auto*

goto*

sizeof

break*

if*

static*

case*

import*+

string+

char

inline

stringof+

const

int

struct

continue*

long

switch*

counter*+

offsetof+

this+

default*

probe*+

translator+

do*

provider*+

typedef

double

register*

union

else*

restrict*

unsigned

enum

return*

void

extern

self+

volatile

float

short

while*

for*

signed

xlate+

In D ist eine Obergruppe der ANSI-C-Schlüsselwörter für die Verwendung als Schlüsselwörter reserviert. Die zur künftigen Nutzung durch D reservierten Schlüsselwörter sind mit „*” gekennzeichnet. Wenn Sie versuchen, ein zur künftigen Nutzung vorgesehenes Schlüsselwort einzusetzen, generiert der D-Compiler einen Syntaxfehler. Die in D, aber nicht in ANSI-C definierten Schlüsselwörter, sind mit „+” gekennzeichnet. D umfasst den vollständigen Satz der ANSI-C-Typen und -Operatoren. Der wesentliche Unterschied zur Programmierung in D besteht im Verzicht auf Kontrollstrukturen. Die in ANSI-C als Kontrollstrukturen dienenden Schlüsselwörter sind in D zur künftigen Verwendung reserviert.

Datentypen und -größen

In D stehen Ihnen die Grunddatentypen für Ganzzahlen- und Fließpunktkonstanten zur Verfügung. In D-Programmen können arithmetische Operationen nur an Ganzzahlen vorgenommen werden. Gleitkommakonstanten sind zum Initialisieren von Datenstrukturen zulässig, aber die Gleitkommaarithmetik ist in D nicht erlaubt. D stellt zum Schreiben von Programmen ein 32-Bit- und 64-Bit-Datenmodell zur Verfügung. Bei der Ausführung des Programms wird das native Datenmodell des aktiven Betriebssystemkernels verwendet. Mit isainfo -b lässt sich das native Datenmodell des jeweiligen Systems ermitteln.

Die folgende Tabelle enthält die Namen der Integer-Typen und ihre Größe in beiden Datenmodellen. In der nativen Byte-Kodierung des Systems werden Integer-Typen stets als Zweierkomplement dargestellt.

Tabelle 2–2 Integer-Datentypen in D

Typname 

32-Bit-Größe 

64-Bit-Größe 

char

1 Byte 

1 Byte 

short

2 Byte 

2 Byte 

int

4 Byte 

4 Byte 

long

4 Byte 

8 Byte 

long long

8 Byte 

8 Byte 

Integer-Typen können das Präfix signed (mit Vorzeichen) oder unsigned (ohne Vorzeichen) erhalten. Wenn kein Vorzeichen-Kennzeichner vorhanden ist, gilt der Datentyp als vorzeichenbehaftet. Der D-Compiler stellt außerdem die Typ-Aliasnamen in folgender Tabelle bereit:

Tabelle 2–3 Aliasnamen für Integer-Typen in D

Typname 

Beschreibung 

int8_t

1-Byte-Integer mit Vorzeichen 

int16_t

2-Byte-Integer mit Vorzeichen 

int32_t

4-Byte-Integer mit Vorzeichen 

int64_t

8-Byte-Integer mit Vorzeichen 

intptr_t

Integer mit Vorzeichen der Größe eines Zeigers 

uint8_t

1-Byte-Integer ohne Vorzeichen 

uint16_t

2-Byte-Integer ohne Vorzeichen 

uint32_t

4-Byte-Integer ohne Vorzeichen 

uint64_t

8-Byte-Integer ohne Vorzeichen 

uintptr_t

Integer ohne Vorzeichen der Größe eines Zeigers 

Diese Typ-Aliasnamen haben die gleiche Wirkung wie die Namen des entsprechenden Grundtyps in der vorigen Tabelle und sind für jedes Datenmodell angemessen definiert. So ist beispielsweise der Typname uint8_t ein Aliasname für den Typ unsigned char. Wie Sie eigene Typ-Aliasnamen für Ihre D-Programme definieren können, erfahren Sie in Kapitel 8Typ- und Konstantendefinitionen.

Aus Gründen der Kompatibilität mit ANSI-C-Deklarationen und -Typen bietet D auch Gleitkommatypen. Gleitkomma-Operatoren werden in D nicht unterstützt. Es ist allerdings möglich, Gleitkomma-Datenobjekte mit der Funktion printf() zu verfolgen und zu formatieren. Die Gleitkommatypen in der folgenden Tabelle sind zulässig:

Tabelle 2–4 Gleitkomma-Datentypen in D

Typname 

32-Bit-Größe 

64-Bit-Größe 

float

4 Byte 

4 Byte 

double

8 Byte 

8 Byte 

long double

16 Byte 

16 Byte 

Außerdem steht in D der spezielle Typ string zur Darstellung von ASCII-Zeichenketten zur Verfügung. Zeichenketten werden in Kapitel 6Zeichenketten näher erläutert.

Konstanten

Integer-Konstanten (Ganzzahlkonstanten) können in dezimaler (12345), oktaler (012345) oder hexadezimaler (0x12345) Form geschrieben werden. Oktale Konstanten (Grundzahl 8) müssen eine Null als Präfix erhalten. Hexadezimalen Konstanten (Grundzahl 16) ist entweder 0x oder 0X voranzustellen. Integer-Konstanten wird der kleinste der Datentypen int, long oder long long zugewiesen, mit dem ihr Wert dargestellt werden kann. Bei negativen Werten wird die vorzeichenbehaftete Version des entsprechenden Typs verwendet. Positive Werte, die zu groß für den Typ mit Vorzeichen sind, werden durch den entsprechenden vorzeichenlosen Typ dargestellt. An jede Integer-Konstante kann zur expliziten Angabe des D-Typs einer der folgenden Zusätze angehängt werden:

u oder U

unsigned-Version des vom Compiler ausgewählten Typs

l oder L

long

ul oder UL

unsigned long

ll oder LL

long long

ull oder ULL

unsigned long long

Gleitkommakonstanten werden immer in dezimaler Form dargestellt und müssen entweder ein Dezimaltrennzeichen (12.345), einen Exponent ( 123e45) oder beides enthalten (123.34e-5). Standardmäßig wird Gleitkommakonstanten der Typ double zugewiesen. An jede Gleitkommakonstante kann zur expliziten Angabe des D-Typs einer der folgenden Zusätze angehängt werden:

f oder F

float

l oder L

long double

Zeichenkonstanten werden als einzelnes Zeichen oder in ihrer Ersatzdarstellung zwischen einfachen Anführungszeichen dargestellt ('a'). Zeichenkonstanten wird der Typ int zugewiesen und sie sind gleichbedeutend mit Integer-Konstanten, deren Wert durch den Wert des entsprechenden Zeichens im ASCII-Zeichensatz bestimmt ist. Eine Liste von Zeichen und ihren Werten finden Sie unter ascii(5). Auch alle speziellen Ersatzdarstellungen in der nachfolgenden Tabelle sind in Zeichenkonstanten erlaubt. D unterstützt dieselben Ersatzdarstellungen, wie sie in ANSI-C verwendet werden.

Tabelle 2–5 Ersatzdarstellungen für Zeichen in D

\a

Klingelzeichen 

\\

Gegenschrägstrich 

\b

Rückschritt (Backspace) 

\?

Fragezeichen 

\f

Seitenvorschub 

\'

(einfaches) Anführungszeichen 

\n

Zeilentrenner 

\”

(doppeltes) Anführungszeichen 

\r

Wagenrücklauf 

\0oo

Oktalwert 0oo

\t

(waagerechter) Tabulator 

\xhh

Hexadezimalwert 0xhh

\v

Vertikal-Tabulator 

\0

Nullzeichen 

Indem Sie mehrere Zeichenangaben zwischen einfache Anführungszeichen setzen, können Sie Ganzzahlen erstellen, deren einzelne Byte je nach der entsprechenden Zeichenangabe initialisiert werden. Die Byte werden ab der Zeichenkonstante von links nach rechts gelesen und der entstehenden Ganzzahl entsprechend der nativen Byte-Reihenfolge des Betriebssystems in der Darstellung Big Endian oder Little Endian zugeordnet. Eine Zeichenkonstante fasst bis zu acht Zeichenangaben.

Durch Schreibung zwischen doppelten Anführungszeichen lassen sich Zeichenkettenkonstanten einer beliebigen Länge zusammensetzen ("hello"). Zeichenkettenkonstanten dürfen keine wörtlichen Zeilentrenner enthalten. Zur Angabe einer neuen Zeile innerhalb einer Zeichenkette verwenden Sie stattdessen die Ersatzdarstellung \n. Alle bereits für Zeichenkonstanten aufgeführten Sonderzeichen-Ersatzdarstellungen dürfen auch in Zeichenkettenkonstanten vorkommen. Ähnlich wie in ANSI-C werden Zeichenketten als Vektoren von Zeichen mit einem abschließenden Nullzeichen (\0) dargestellt, das implizit an jede deklarierte Zeichenkettenkonstante angefügt wird. Zeichenkettenkonstanten wird der spezielle D-Typ string zugewiesen. Der D-Compiler verfügt über besondere Leistungsmerkmale zum Vergleichen und Verfolgen von Zeichenvektoren, die als Zeichenketten deklariert wurden. Mehr darüber erfahren Sie inKapitel 6Zeichenketten.

Arithmetische Operatoren

D stellt Ihnen für Ihre Programme die binären arithmetischen Operatoren in der nachfolgenden Tabelle zur Verfügung. Diese Operatoren haben dieselbe Bedeutung für Ganzzahlen wie in ANSI-C.

Tabelle 2–6 Binäre arithmetische Operatoren in D

+

Addition von Ganzzahlen 

-

Subtraktion von Ganzzahlen 

*

Multiplikation von Ganzzahlen 

/

Division von Ganzzahlen 

%

Restwert von Ganzzahlen 

Arithmetische Operationen sind in D ausschließlich an Ganzzahlen-Operanden oder, wie in Kapitel 5Zeiger und Vektoren erläutert, an Zeigern möglich. Auf Gleitkomma-Operanden lassen sich arithmetische Operationen in D-Programmen nicht anwenden. Die DTrace-Ausführungsumgebung nimmt keinerlei Einfluss auf Integer-Überläufe oder -Unterläufe. Bei bestehendem Über- und Unterlaufrisiko müssen Sie selbst auf diese Bedingungen prüfen.

Die DTrace-Ausführungsumgebung prüft automatisch auf Divisionen durch Null und meldet derartige Fehler, die durch eine falsche Verwendung der Operatoren / und % entstehen. Wenn ein D-Programm eine ungültige Division durchführt, deaktiviert DTrace die betreffende Instrumentation automatisch und meldet den Fehler. Von DTrace erkannte Fehler haben keinerlei Auswirkungen auf andere DTrace-Benutzer oder den Betriebssystemkernel. Sollte Ihr D-Programm einen dieser Fehler enthalten, müssen Sie sich also keine Sorgen machen, dass es Schaden anrichten könnte.

Neben diesen binären Operatoren sind + und - auch als unäre Operatoren verwendbar. Sie haben eine höhere Priorität als alle binären arithmetischen Operatoren. Die Eigenschaften in Bezug auf Rangfolge und Assoziativität aller D-Operatoren wird in Tabelle 2–11 dargestellt. Die Rangfolge lässt sich durch Zusammenfassen von Ausdrücken in Klammern ( ) beeinflussen.

Relationale Operatoren

D stellt Ihnen für Ihre Programme die binären relationalen Operatoren (Vergleichsoperatoren) in folgender Tabelle zur Verfügung. Diese Operatoren haben dieselbe Bedeutung wie in ANSI-C.

Tabelle 2–7 Relationale Operatoren in D

<

Operand auf linker Seite ist kleiner als Operand auf rechter Seite 

<=

Operand auf linker Seite ist kleiner als oder gleich dem Operanden auf rechter Seite 

>

Operand auf linker Seite ist größer als Operand auf rechter Seite 

>=

Operand auf linker Seite ist größer als oder gleich dem Operanden auf rechter Seite 

==

Operand auf linker Seite ist gleich dem Operanden auf rechter Seite 

!=

Operand auf linker Seite ist ungleich dem Operanden auf rechter Seite 

Relationale Operatoren werden meistens zum Schreiben von D-Prädikaten eingesetzt. Jeder Operator ergibt einen Wert des Typs int, der gleich 1 ist, wenn die Bedingung wahr ist und Null, wenn sie falsch ist.

Relationale Operatoren können auf Paare von Ganzzahlen, Zeigern oder Zeichenketten angewendet werden. Beim Vergleich von Zeigern ist das Ergebnis gleichbedeutend mit einem Integer-Vergleich der zwei als vorzeichenlose Ganzzahlen interpretierten Zeiger. Das Ergebnis eines Vergleichs von Zeichenketten wird wie durch Anwendung von strcmp(3C) auf die beiden Operanden ermittelt. Sehen Sie hier einige Beispiele für Zeichenkettenvergleiche in D und ihre Ergebnisse:

"coffee" < "espresso"

... gibt 1 (wahr) zurück 

"coffee" == "coffee"

... gibt 1 (wahr) zurück 

"coffee" >= "mocha"

... gibt 0 (falsch) zurück 

Relationale Operatoren können auch zum Vergleichen eines einem Aufzählungstyp zugewiesenen Datenobjekts mit einem beliebigen der Enumerator-Tags verwendet werden, die im Aufzählungstyp definiert sind. Aufzählungstypen ermöglichen die Erstellung benannter Ganzzahlkonstanten. Kapitel 8Typ- und Konstantendefinitionen befasst sich ausführlich mit Aufzählungen.

Logische Operatoren

D stellt Ihnen für Ihre Programme die folgenden binären logischen Operatoren zur Verfügung. Die ersten beiden Operatoren sind gleichbedeutend mit den entsprechenden ANSI-C-Operatoren.

Tabelle 2–8 Logische Operatoren in D

&&

Logisches UND: wahr, wenn beide Operanden wahr sind

||

Logisches ODER: wahr, wenn einer oder beide Operanden wahr sind

^^

Logisches EXKLUSIV-ODER: wahr, wenn genau ein Operand wahr ist

Logische Operatoren werden meistens zum Schreiben von D-Prädikaten eingesetzt. Der logische UND-Operator führt eine Short-Circuit-Evaluation durch: Wenn der Operand auf der linken Seite falsch ist, wird der weiter rechts stehende Ausdruck nicht mehr ausgewertet. Auch der logische ODER-Operator führt eine Short-Circuit-Evaluation durch: Wenn der Operand auf der linken Seite wahr ist, wird der weiter rechts stehende Ausdruck nicht mehr ausgewertet. Beim logischen EXKLUSIV-ODER-Operator erfolgt die Auswertung ohne Short-Circuit: Es werden stets beide Operanden des Ausdrucks ausgewertet.

Zusätzlich zu den binären logischen Operatoren steht der unäre !-Operator für logische Negierungen eines einzelnen Operanden zur Verfügung: Er konvertiert einen Operanden gleich Null in Eins und einen Operanden ungleich Null in eine Null. D-Programmierer verwenden ! konventionsgemäß beim Umgang mit Ganzzahlen, die boolesche Werte darstellen sollen, und == 0 bei nicht-booleschen Ganzzahlen. Die beiden Ausdrücke sind jedoch eigentlich bedeutungsgleich.

Die logischen Operatoren können auf Operanden der Integer- oder Zeigertypen angewendet werden. Zeiger-Operanden werden von den logischen Operatoren als ganzzahlige Werte ohne Vorzeichen interpretiert. Wie bei allen logischen und relationalen Operatoren in D sind auch hier die Operanden wahr, wenn sie einen ganzzahligen Wert ungleich Null und falsch, wenn sie einen ganzzahligen Wert gleich Null aufweisen.

Bitweise Operatoren

D bietet die folgenden binären Operatoren zur Manipulation einzelner Bits innerhalb von numerischen Operanden. Diese Operatoren haben dieselbe Bedeutung wie in ANSI-C.

Tabelle 2–9 Bitweise Operatoren in D

&

Bitweises UND 

|

Bitweises ODER 

^

Bitweises EXKLUSIV-ODER 

<<

Operand auf linker Seite um die mit dem Operanden auf der rechten Seite angegebene Bitanzahl nach links verschieben 

>>

Operand auf linker Seite um die mit dem Operanden auf der rechten Seite angegebene Bitanzahl nach rechts verschieben 

Der binäre Operator & dient zum Löschen von Bits aus einem ganzzahligen Operanden. Der binäre Operator | dient zum Einsetzen von Bits in einen ganzzahligen Operanden. Der binäre Operator ^ gibt an jeder Bitposition eine 1 zurück, an der exakt eines der entsprechenden Operand-Bits gesetzt ist.

Mit den Schiebeoperatoren lassen sich Bits innerhalb eines gegebenen Integer-Operanden nach links oder rechts verschieben. Durch eine Linksverschiebung werden leere Bitpositionen auf der rechten Seite des Ergebnisses mit Nullen gefüllt. Durch eine Rechtsverschiebung mit vorzeichenlosem Integer-Operanden werden leere Bitpositionen auf der linken Seite des Ergebnisses mit Nullen gefüllt. Bei einer Rechtsverschiebung mit vorzeichenbehaftetem Integer-Operanden werden leere Bitpositionen auf der linken Seite mit dem Wert des Vorzeichenbits gefüllt. Dies wird auch als arithmetische Verschiebung bezeichnet.

Die Verschiebung eines ganzzahligen Werts um eine negative Bitanzahl oder eine Bitanzahl, die größer ist als die Anzahl der Bits im linken Operanden selbst, ergibt ein unbestimmtes Resultat. Wenn diese Bedingung beim Kompilieren des D-Programms vom D-Compiler erkannt wird, generiert dieser eine Fehlermeldung.

Zusätzlich zu den binären logischen Operatoren steht der unäre ~-Operator für bitweise Negierungen eines einzelnen Operanden zur Verfügung: Er konvertiert jedes Nullbit im Operanden in ein 1-Bit und jedes 1-Bit im Operanden in ein Nullbit.

Zuweisungsoperatoren

D bietet die folgenden binären Zuweisungsoperatoren zum Ändern von D-Variablen. Nur D-Variablen und Vektoren lassen sich ändern. Kerneldatenobjekte und Konstanten können mit den D-Zuweisungsoperatoren nicht geändert werden. Die Zuweisungsoperatoren haben dieselbe Bedeutung wie in ANSI-C.

Tabelle 2–10 Zuweisungsoperatoren in D

=

Linken Operanden mit rechtem Ausdruckswert gleichsetzen 

+=

Linken Operanden um den rechten Ausdruckswert erhöhen 

-=

Linken Operanden um den rechten Ausdruckswert verringern 

*=

Linken Operanden mit dem rechten Ausdruckswert multiplizieren 

/=

Linken Operanden durch den rechten Ausdruckswert dividieren 

%=

Rest des linken Operanden mit dem rechten Ausdruckswert als Divisor errechnen 

|=

Bitweise ODER-Operation an linkem Operanden mit rechtem Ausdruckswert durchführen 

&=

Bitweise UND-Operation an linkem Operanden mit rechtem Ausdruckswert durchführen 

^=

Bitweise EXKLUSIV-ODER-Operation an linkem Operanden mit rechtem Ausdruckswert durchführen 

<<=

Operanden auf linker Seite um die mit dem Ausdruckswert auf der rechten Seite angegebene Bitanzahl nach links verschieben 

>>=

Operanden auf linker Seite um die mit dem Ausdruckswert auf der rechten Seite angegebene Bitanzahl nach rechts verschieben 

Alle Zuweisungsoperatoren außer = dienen als Kurzform für die Verwendung des Operators = mit einem der weiter oben beschriebenen Operatoren. So ist beispielsweise der Ausdruck x = x + 1 gleichwertig mit dem Ausdruck x += 1, bis auf die Tatsache, dass der Ausdruck x einmal ausgewertet wird. Diese Zuweisungsoperatoren unterliegen denselben Regeln für Operandentypen wie die bereits beschriebenen binären Formen.

Das Ergebnis jedes Zuweisungsoperators ist ein Ausdruck gleich dem neuen Wert des Ausdrucks auf der linken Seite. Sie können die Zuweisungsoperatoren sowie alle bisher genannten Operatoren kombinieren, um Ausdrücke von beliebiger Komplexität zu formen. Terme in komplexen Ausdrücken können durch Klammern ( ) gruppiert werden.

Inkrement- und Dekrement-Operatoren

In D stehen Ihnen die speziellen unären Operatoren ++ und -- zum Erhöhen und Verringern von Zeigern und Ganzzahlen zur Verfügung. Diese Operatoren haben dieselbe Bedeutung wie in ANSI-C. Sie sind nur auf Variablen anwendbar und können vor oder nach dem Variablennamen stehen. Wenn der Operator vor dem Variablennamen steht, wird zuerst die Variable geändert und der resultierende Ausdruck dann dem neuen Wert der Variable gleichgesetzt. Beispielsweise ergeben die zwei folgenden Ausdrücke identische Resultate:

x += 1;

y = ++x;

y = x;

 

Steht der Operator nach dem Variablennamen, dann wird die Variable erst verändert, nachdem ihr aktueller Wert zur Verwendung im Ausdruck zurückgegeben wurde. Beispielsweise ergeben die zwei folgenden Ausdrücke identische Resultate:

y = x;

y = x--;

x -= 1;

 

Mit den Inkrement- und Dekrement-Operatoren können Sie neue Variablen erstellen, ohne sie zu deklarieren. Wenn Sie eine Variablendeklaration unterlassen und den Inkrement- oder Dekrement-Operator auf eine Variable anwenden, wird die Variable implizit als Typ int64_t erklärt.

Die Inkrement- und Dekrement-Operatoren lassen sich auf Ganzzahl- oder Zeigervariablen anwenden. Bei Anwendung auf Ganzzahlvariablen erhöhen bzw. verringern die Operatoren den entsprechenden Wert um 1. Werden sie auf Zeigervariablen angewendet, erhöhen bzw. verringern die Operatoren die Zeigeradresse um die Größe des mit dem Zeiger referenzierten Datentyps. Zeiger und Zeigerarithmetik in D werden in Kapitel 5Zeiger und Vektoren behandelt.

Bedingte Ausdrücke

D unterstützt zwar keine if-then-else-Konstrukte, bietet aber Unterstützung für einfache bedingte Ausdrücke unter Verwendung der Operatoren ? und : . Diese Operatoren ermöglichen die Zuweisung von Dreiergruppen von Anweisungen, in denen der erste Ausdruck zur bedingten Auswertung eines der anderen beiden dient. Beispielsweise könnte die folgende D-Anweisung verwendet werden, um eine Variable x je nach dem Wert von i auf eine von zwei Zeichenketten zu setzen:

x = i == 0 ? "zero" : "non-zero";

In diesem Beispiel wird zunächst der Ausdruck i == 0 ausgewertet, um festzustellen, ob er wahr oder falsch ist. Ist der erste Ausdruck wahr, wird der zweite Ausdruck ausgewertet und der Ausdruck ?: gibt seinen Wert zurück. Ist der erste Ausdruck falsch, wird der dritte Ausdruck ausgewertet und der Ausdruck ?: gibt seinen Wert zurück.

Wie bei allen D-Operatoren können Sie in einem Ausdruck mehrere ?:-Operatoren verwenden und so komplexere Ausdrücke generieren. So würde beispielsweise der folgende Ausdruck die eines der Zeichen 0-9, a-z oder A-Z enthaltende char-Variable c nehmen und den Wert dieses Zeichens zurückgeben, wenn es als Ziffer in einer hexadezimalen (Grundzahl 16) Zahl interpretiert wird:

hexval = (c >= '0' && c <= '9') ? c - '0' :
    (c >= 'a' && c <= 'z') ? c + 10 - 'a' : c + 10 - 'A';

Der erste mit ?: verwendete Ausdruck muss ein Zeiger auf eine Ganzzahl sein, damit er auf seinen Wahrheitswert hin untersucht werden kann. Beim zweiten und dritten Ausdruck kann es sich um einen beliebigen kompatiblen Typ handeln. Die Konstruktion eines bedingten Ausdrucks ist nicht möglich, wenn beispielsweise ein Pfad eine Zeichenkette und ein anderer Pfad eine Ganzzahl zurückgibt. Außerdem dürfen der zweite und der dritte Ausdruck keine Ablaufverfolgungsfunktion wie trace() oder printf() aufrufen. Zur bedingten Ablaufverfolgung von Daten greifen Sie, wie in Kapitel 1Einführung erläutert, stattdessen auf Prädikate zurück.

Typumwandlungen

Bei der Konstruktion von Ausdrücken mit Operanden unterschiedlicher, aber kompatibler Typen werden Typumwandlungen zur Bestimmung des Typs des resultierenden Ausdrucks vorgenommen. Die D-Regeln für Typumwandlungen stimmen mit den Regeln für die arithmetische Konvertierung von Ganzzahlen in ANSI-C überein, die auch als normale arithmetische Umwandlungen bezeichnet werden.

Die Umwandlungsregeln lassen sich auf einfache Weise wie folgt beschreiben: Jeder Integer-Typ hat eine Priorität nach der Rangfolge char, short, int, long, long long. Dabei hat ein vorzeichenloser Typ gegenüber seiner vorzeichenbehafteten Entsprechung eine höhere, gegenüber dem in der Rangfolge nächsten Integer-Typ aber eine niedrigere Priorität. Wenn Sie einen Ausdruck mit zwei ganzzahligen Operanden wie x + y formulieren und die Operanden unterschiedliche Integer-Typen aufweisen, wird dem Ergebnis der Typ des Operanden mit der höchsten Priorität zugewiesen.

Sollte eine Umwandlung erforderlich sein, wird der in der Rangfolge niedrigere Operand zunächst auf den nächst höheren Typ erweitert. Durch die Typerweiterung wird der Wert des Operanden nicht wirklich geändert: Es erfolgt lediglich eine Erweiterung seiner Wertemenge im Einklang mit dem Vorzeichen des Werts. Bei einer Typerweiterung eines vorzeichenlosen Operanden werden die nicht verwendeten höherwertigen Bits in der resultierenden Ganzzahl mit Nullen aufgefüllt. Bei einer Typerweiterung eines vorzeichenbehafteten Operanden werden die nicht verwendeten höherwertigen Bits durch eine Vorzeichenerweiterung angefüllt. Wenn ein vorzeichenbehafteter Typ in einen vorzeichenlosen umgewandelt wird, erfolgt zunächst eine Vorzeichenerweiterung des vorzeichenbehafteten Typs und anschließend erhält dieser den neuen, durch die Umwandlung bestimmten vorzeichenlosen Typ.

Integer- und andere Typen können auch explizit von einem Typ in einen anderen umgewandelt werden. Die explizite Typumwandlung wird auch als Cast bezeichnet. In D ist die explizite Typumwandlung von Zeigern und Ganzzahlen in beliebige Integer- oder Zeigertypen, nicht aber in andere Typen möglich. Die Regeln für das Casting und die Typerweiterung von Zeichenketten und Zeichenvektoren werden in Kapitel 6Zeichenketten besprochen. Eine explizite Typumwandlung einer Ganzzahl oder eines Zeigers erfolgt anhand eines Ausdrucks wie diesem:

y = (int)x;

wobei der Zieltyp eingeklammert ist und als Präfix für den Ausgangsausdruck dient. Die explizite Typumwandlung von Ganzzahlen in höherwertige Typen erfolgt über eine Typerweiterung. Zur expliziten Typumwandlung von Ganzzahlen in niederwertige Typen werden die überschüssigen höherwertigen Bits in der Ganzzahl mit Nullen aufgefüllt.

Da D keine Gleitkomma-Arithmetik zulässt, ist auch keine implizite oder explizite Umwandlung von Gleitkomma-Operanden erlaubt und sind keine Regeln für die implizite Gleitkomma-Typumwandlung definiert.

Rangfolge

Die D-Regeln für die Operatorrangfolge (auch Präzedenz oder Priorität) und Assoziativität sind in der folgenden Tabelle dargestellt. Diese Regeln sind recht komplex, aber erforderlich für die Gewährleistung einer genauen Kompatibilität mit den ANSI-C-Regeln für die Operatorrangfolge. Die Einträge sind nach absteigender Rangfolge sortiert.

Tabelle 2–11 Operatorrangfolge und Assoziativität in D

Operatoren 

Assoziativität 

() [] -> .

rechtsassoziativ 

! ~ ++ -- + - * & (Typ) sizeof stringof offsetof xlate

linksassoziativ 

* / %

rechtsassoziativ 

+ -

rechtsassoziativ 

<< >>

rechtsassoziativ 

< <= > >=

rechtsassoziativ 

== !=

rechtsassoziativ 

&

rechtsassoziativ 

^

rechtsassoziativ 

|

rechtsassoziativ 

&&

rechtsassoziativ 

^^

rechtsassoziativ 

||

rechtsassoziativ 

?:

linksassoziativ 

= += -= *= /= %= &= ^= |= <<= >>=

linksassoziativ 

,

rechtsassoziativ 

Einige der Operatoren in dieser Tabelle sind uns bisher noch nicht begegnet. Sie werden in späteren Kapiteln besprochen:

sizeof

Berechnet die Größe eines Objekts (Kapitel 7Strukturen und Unionen)

offsetof

Berechnet den Versatz einer Typkomponente (Kapitel 7Strukturen und Unionen)

stringof

Wandelt den Operanden in eine Zeichenkette um (Kapitel 6Zeichenketten)

xlate

Übersetzt einen Datentyp (Kapitel 40Übersetzer)

unäres &

Berechnet die Adresse eines Objekts (Kapitel 5Zeiger und Vektoren)

unäres *

Dereferenziert einen Zeiger auf ein Objekt (Kapitel 5Zeiger und Vektoren)

-> und .

Greift auf die Komponente einer Struktur bzw. einer Union zu(Kapitel 7Strukturen und Unionen)

Der in der Tabelle aufgeführte Komma-Operator (,) dient zur Gewährleistung der Kompatibilität mit dem Komma-Operator in ANSI-C, mit dem eine Reihe von Ausdrücken rechtsgerichtet ausgewertet und der Wert des am weiten rechts stehenden Ausdrucks zurückgegeben werden kann. Dieser Operator wird ausschließlich aus Kompatibilitätsgründen bereitgestellt und sollte nicht verwendet werden.

Der Eintrag () in der Tabelle der Operatorrangfolge stellt einen Funktionsaufruf dar. Beispiele für Aufrufe von Funktionen wie printf() oder trace() finden Sie in Kapitel 1Einführung. Kommata werden in D auch zum Auflisten von Argumenten für Funktionen und zum Erstellen von Schlüsseln für assoziative Vektoren verwendet. Dieses Komma ist nicht mit dem Komma-Operator identisch und garantiert keine rechtsgerichtete Auswertungsreihenfolge. Der D-Compiler bietet keine Garantie in Bezug auf die Auswertungsreihenfolge der Argumente einer Funktion oder der Schlüssel eines assoziativen Vektors. Bei der Verwendung von Ausdrücken mit interagierenden Nebeneffekten, wie beispielsweise des Ausdruckspaars i und i++, ist in diesem Kontext Vorsicht geboten.

Der Eintrag [] in der Tabelle der Operatorrangfolge stellt eine Referenz auf einen Vektor oder einen assoziativen Vektor dar. Beispiele für assoziative Vektoren finden Sie in Kapitel 1Einführung. Eine Sonderform des assoziativen Vektors, das Aggregat, wird in Kapitel 9Aggregate beschrieben. In Kapitel 5Zeiger und Vektoren erfahren Sie, wie der Operator [] auch zum Indizieren von C-Vektoren fester Größe eingesetzt werden kann.