4. Grundlagen von Programmiersprachen - Einfache Typen, Ausdrücke, Typanpassung 4.1 4.2 4.3 4.4 Datentypen Ausdrücke Typanpassung Vereinbarung von Variablen und deren Typen 4.1 Datentypen (1) z Programmiersprache heißt getypt (strong typing), wenn - jede Variable - jedes Literal - jeder Ausdruck z z int myVar; "Zeichenkette" 220/2 Java einen (Daten-)typ besitzt. Zu jedem Typ T: Menge von Operatoren, die auf Werten von T definiert sind Statisch getypte Sprache (static typing): Korrekter Typ ("darf Operator angewendet werden?") wird vor Ausführung des Programms geprüft. hs / fub - alp2-04 2 Einfache Datentypen ganze Zahlen Zahlen 1. Elementare (primitive) DT int, byte, long Zeichen char Wahrheitswerte boolean Aufzählungtypen 2. Benutzerdefinierte DT public enum Weekend {SA,SU} (seit Java 1.5) Bereiche [10..20] (nicht in Java) Weitere (zusammengesetzte) Typen: - Felder Aus Teilen zusammengesetzt, die einzeln manipuliert werden - Klassen können. Oft rekursives Konstruktionsprinzip ! r e t ä p S hs / fub - alp2-04 3 Wertebereiche von Zahldatentypen in Java public class BoundsOfNumbers { public static void main (String[] args) { System.out.println(" byte=["+Byte.MIN_VALUE+".."+Byte.MAX_VALUE+"]"); System.out.println(" short=["+Short.MIN_VALUE+".."+Short.MAX_VALUE+"]"); System.out.println(" int=["+Integer.MIN_VALUE+".."+Integer.MAX_VALUE+"]"); System.out.println(" long=["+Long.MIN_VALUE+".."+Long.MAX_VALUE+"]"); System.out.println(" float=["+Float.MIN_VALUE+".."+Float.MAX_VALUE+"]"); System.out.println("double=["+Double.MIN_VALUE+".."+Double.MAX_VALUE+"]"); System.out.println("double=["+Double.NEGATIVE_INFINITY+".." +Double.POSITIVE_INFINITY+"]"); System.out.println("Infinity+1: " + (Double.MAX_VALUE+1.0)); System.out.println(" Maxint+1 ="+(Integer.MAX_VALUE+1)); } byte=[-128..127] short=[-32768..32767] int=[-2147483648..2147483647] long=[-9223372036854775808..9223372036854775807] float=[1.4E-45..3.4028235E38] double=[4.9E-324..1.7976931348623157E308] double=[-Infinity..Infinity] Infinity+1: 1.7976931348623157E308 Maxint+1 =-2147483648 hs / fub - alp2-04 4 Charakterisierung von Datentypen - Repräsentation von Werten ? Beispiel: 16-Bit-Unicode Zeichendarstellung in Java Nicht sinnvoll! Implementierungsabhängig. - Operatoren, die auf Werte des Typs angewendet werden können Beispiel: Addition (+), Multiplikation (*), Subtraktion (-) auf allen numerischen Datentypen hs / fub - alp2-04 5 Allen Datentypen gemeinsame Operationen: (1) Vergleichsoperatoren: == Gleichheit a == b hat Wert true, wenn a=b, sonst false Ergebnis: Bool'scher Wert != Ungleichheit a != b ... wenn a≠b Vergleiche Haskell: == und /= Warum in Haskell Vergleichsoperatoren nicht für alle Typen definiert? class Eq hs / fub - alp2-04 6 (2) Zuweisungsoperator <variable> = <Ausdruck> ist [in Java] ein Ausdruck, der einen Wert hat und als Nebeneffekt diesen Wert der <variable> zuweist. int i=2,j=3,m; System.out.println("i+j: "+ (m = i+j)); (ternärer Operator) der bedingungsabhäng(3) wenn – dann – sonst ig einen von zwei Werten liefert. Java-Syntax: <bedingung> ? <wert1> : <wert2> i > 0 ? i : -i Nicht mit Fallunterscheidung verwechseln: if <bed> {Anweisung1} else {Anweisung2}; hs / fub - alp2-04 7 Datentypen und Operationen [in Java] Wahrheitswerte boolean Literale: true, false Operationen: ! &, &= |, |= && || Negation Konjunktion, mit Zuweisung an ersten Operanden Disjunktion, mit Zuweisung an ersten Operanden Konjunktion, nichtstrikt im 2.Operanden Disjunktion, nichtstrikt im 2. Operanden boolean b1 = true, b2 = true, b3= false; b1 &= b3; System.out.println("b1="+b1); b2 = b1 &&(0/0==0); System.out.println("b2="+b2); b1=false b2=false hs / fub - alp2-04 8 Zeichen char Literale: 'a,'b',..., '\f',...,\u0000 Achtung: Unbedingt Details zu Datentypen in Java aus (Hand-) Buch entnehmen. Repräsentiert durch 16 Bit Unicode Operationen: ++, --, +, liefert das Nachfolge-, Vorgängerzeichen char c = 'c' ++c == 'd' auch als postfix: char x = c++; x=='d' nicht 'e' (wegen c=='d') char x, y='c'; System.out.println("y="+(++y)+ ", x=" +(x=y++)+ ", y=" +y); y=d, x=d, y=e hs / fub - alp2-04 9 Zahlen (1) Ganze Zahlen int 32 Bits Zweierkomplement int=[-2147483648..2147483647] Dezimale, oktale (0 und Ziffern 0-7) und hexadezimale (0x und Ziffern 0-9,a,b,c,d,e,f) Darstellung Beachte 55 ≠ 055 ≠ 0x55 Weitere Repräsentationen: long 64 Bits Werte: <ziffernfolge>L 12345678L (angehängtes L oder l; besser: L ) short byte 16 Bits 8 Bits, [-128 .. 127], Zweierkomplement! Initialwert: 0 hs / fub - alp2-04 10 Operationen auf ganzen Zahlen unär: + - (Vorgänger, Nachfolger) binär: + - * (ohne Überlaufkontrolle) / (ganzzahlig) int i = 123456789; % mit: System.out.println(" ++ -- a % b =a- a ⎣b⎦ *b i="+(i*100)); i=-539222988 Sonstige Operationen & += | bitweise und, oder, exklusives oder ^ -= *= /= %= &= |= ^= Operation mit Zuweisung an linken Operanden < <= > >= Vergleichsoperatoren hs / fub - alp2-04 11 (2) Gebrochene Zahlen double float 64-Bit Gleitpunktformat für rationale Zahlen 32-Bit Gleitpunktformat (gemäß IEEE 754 Spezifikation) Werte: Dezimalzahlen mit/ohne Dezimalpunkt, mit/ohne angehängten Exponenten E<ganze Zahl> oder e<ganze Zahl> (= e) Float-Werte müssen durch angehängtes n gekennzeichnet sein. 27182818E-7 27182818E-7f Weitere gemäß IEEE: POSITIVE_INFINITY NEGATIVE_INFINITY NaN (not a number, z.B. 0/0) Initialwert: 0.0 bzw. 0.0F hs / fub - alp2-04 12 Operationen auf gebrochenen Zahlen: wie auf ganzen Zahlen, außer Bit-Operationen z.B. e%2: 0.8182819 Vorsicht beim Rechnen mit Gleitkommazahlen! double euros1 = 0.01 + 0.05 + 0.10 + 0.25; double euros2 = 0.25 + 0.10 + 0.05 + 0.01; System.out.println("Euro1="+euros1); System.out.println("Euros="+euros2); Euro1=0.41000000000000003 Euros=0.41 hs / fub - alp2-04 13 … Fehler bei Gleitkommaoperationen e*55/55-e : 0.0 e-55+55-e != 0: true ⇒ nie auf (Un-)Gleichheit testen Assoziativität? (0.01f + 12345678)-12345678 :0.0 0.01f + (12345678-12345678) :0.1 Gründe: unvermeidliche Rundungsfehler, Binär statt Dezimaldarstellung. z.B. unendliche Dezimal- / Binärbrüche hs / fub - alp2-04 14 Dezimale Datentypen (nicht in Java) - Konversionen vermeiden - Nützlich / wichtig in Finanz- und Wirtschaftsanwendungen - Heute fast nur in Software - Sprachen: C++, COBOL, PL/1, SQL (Datenbanksprache) - Unterstützung durch Dezimalarithmetikeinheit möglich. Vorzeichen Prinzip: Bytegrenze Pro Halbbyte eine dezimale Ziffer (mit Pseudotretraden), Dezimalpunkt per Software. hs / fub - alp2-04 15 Datentyp ist definiert durch die auf Werten dieses Typs erlaubten Operationen – nicht durch seine Repräsentation (Implementierung). Verschiedene DT können gemeinsame Operationen besitzen, +, *, - auf allen Zahltypen definiert, aber völlig verscheiden implementiert. Trennung von Eigenschaften ("Spezifikation") und Realisierung wichtiges Grundprinzip der Informatik. ⇒ Abstrakte Datentypen … später hs / fub - alp2-04 16 Die einfachsten nichtprimitiven Typen: enum, array Aufzählungstypen (enumeration type) Endliche Menge von Konstanten (Werten), deren Bezeichner (Namen)vom Programmierer in einer Typedefinition festgelegt werden. Java: seit 1.5 public enum Obst {APFEL,BIRNE,PFLAUME} Achtung: enum Typen gibt es in vielen Programmiersprachen - C, C++, Modula-2, Delphi, Haskell (algebraische Typen!), Ada … - die Semantik ist jedoch sehr unterschiedlich. Im einfachsten Fall: Verwendung zu Dokumentationszwecken hs / fub - alp2-04 17 Datentyp Feld (array) Repräsentiert eine Folge fester Länge von Variablen des gleichen Datentyps <typ> [] <name> = {<werte>} int[] prim5 = {2,3,5,7,7+4} Index der Folgenelemente: 0..(n-1) für Folge der Länge n Zugriff auf i-tes Folgenelement: <feldname>[i] Beispiel: prim5[0] + prim5[4] == 13 Felder gibt es in praktisch jeder Programmiersprache. hs / fub - alp2-04 18 Grafik aus Java Tutorium (Sun) Besonderheit von Feldern in Java un r ä l Erk r. te ä p s ohne Angabe der Werte ist möglich (sogar Normalfall), das eigentliche Feld mit definierter Länge erhält man dann erst durch eine Operation: <typ> [] <name> = new <typ>[zahl] char[] zeile = new char[80] Vereinbarung <typ> [] <name>; char[] zeile; r ü f a gd hs / fub - alp2-04 19 4.2 Ausdrücke (expressions) Einfache Ausdrücke: Literal 54 , Variable i , 'c' tmp Konstante PI Zusammengesetzte Ausdrücke unärer -54 -tmp binärer 3*4.0 5*PI -3 konditionaler tmp < 0 ? –tmp : tmp Zuweisung tmp = i+3 geklammerter Ausdruck (j=3+i) Weitere Ausdrücke, z.B. Funktionsaufrufe: sin(0.342) Jeder Ausdruck hat einen Wert. hs / fub - alp2-04 20 Einschränkungen z Ausdruck muss syntaktisch korrekt sein ⇐ Syntaxanalyse des Übersetzers (Parser) z Ausdruck muss typkorrekt sein ⇐ Semantische Analyse Beispiel: a+12 ==i && c typkorrekt, wenn a und i den Typ int haben, c den Typ boolean. Aber: Typanpassung möglich! s.u. hs / fub - alp2-04 21 Bindungsstärke von Operatoren Wie wird a+12 == i && c ausgewertet? Woran erkennt Parser die Auswertungsreihenfolge ((a+12) == i) && c ? Explizite Klammerung immer möglich, sonst Operatorvorrang (Bindungsstärke, Operatorpräzedenz) aus Java-Tutorial (Sun) Operators Precedence postfix expr++ expr-- unary ++expr --expr +expr expr ~ ! multiplicative */% additive +- shift << >> >>> relational < > <= >= equality == != bitwise AND & bitwise exclusive OR ^ bitwise inclusive OR | logical AND && logical OR || ternary ?: assignment = += -= *= /= %= &= ^= |= <<= >>= >>>= fallend hs / fub - alp2-04 22 Assoziativität von Operatoren Für kommutative Operatoren uninteressant !? Nein: (0.01f + 12345678)-12345678 != 0.01f + (12345678-12345678) Binäre (dyadische) Operatoren werden bei gleicher Bindungsstärke immer linksassoziativ geklammert und ausgewertet: a+b-c+d == ((a+b)-c)+d Ausnahme: Zuweisung a=b=c a=(b=c) Ternäre Operation rechtsassoziativ a ? b : c ? d :e == a ? b : (c? d : e) Dringende Empfehlung: im Zweifelsfall explizit klammern! hs / fub - alp2-04 23 Auswertung von Ausdrücken (1) Einfache Ausdrücke: Wert den sie bezeichnen (2) Zusammengesetzte Ausdrücke: (a) Auswertung von links nach rechts * (b) Beachtung der Bindungsstärke und Klammerung (c) Auswertung aller Operanden vor Anwendung des Operators (eager evaluation)** * Ausnahme: ternäre Operation (_?_:_) ** Ausnahme: nichtstrikte Operationen && , ||, (_?_:_) hs / fub - alp2-04 24 4.3 Typanpassung a = b + c : wann ist der Ausdruck typkorrekt? Grundidee: in einer Zuweisung x = y muss y einen Typ haben, der ohne Informationsverlust in den von x überführt werden kann. Beachte: nicht symmetrisch! Beispiel: double x, int y; x=y; y=x; // int in double wandeln 9 // Compiler meldet Fehler hs / fub - alp2-04 25 Typverträglichkeit ( ∠ ) primitiver Typen (1) Jeder Typ ist mit sich selbst verträglich: T ∠ T (2) Wenn a mit b, b mit c verträglich, dann a mit c T1 ∠ T2, T2 ∠ T3 ⇒ T1 ∠ T3 (3) In Java: byte ∠ short ∠ int ∠ long ∠ float ∠ double und char ∠ int boolean ist nur mit sich selbst verträglich Automatische Typanpassung, wenn verträglich, also kein Informationsverlust. hs / fub - alp2-04 26 double d = 1.0 ; int i = 077; short s = 2; float f = 1.0F; d = i; // erlaubt d = f; // erlaubt d = 'a'; // erlaubt! a==97.0 // f = 1.0; // Statischer Typfehler s = 'a'; // Statischer Typfehler?! erlaubt // Kuriosum des Typsystems, // Wert 'passt' in Variable f = 1234567890123L; // erlaubt, Genauigkeitsverlust Statische Typprüfung während der Übersetzung hs / fub - alp2-04 27 Automatische Wertumwandlung zur Laufzeit Liegt wird T1-Wert benötigt, aber T2-Wert liegt vor, dann wird T2-Wert in T1-Wert umgewandelt. doubleVar = intVar; Repräsentation im 2er-Komplement wird in Gleitpunktdarstellung umgewandelt. Wenn gemäß Typverträglichkeit: widening conversion Was geschieht mit doubleVar + intVar? hs / fub - alp2-04 28 Typumwandlung in Ausdrücken Kleinerer Typ wird in größeren umgewandelt, damit Operator anwendbar ist. Ausnahme (Java): int ist der kleinste gemeinsame Typ, d.h. shortVar = shortVar + byteVar liefert statischen Typfehler ("cannot convert from int to short") shortVar + byteVar Werte der Variablen werden in int-Darstellung umgewandelt, der kann nicht (ohne Weiteres) einer short-Variablen zugewiesen werden. hs / fub - alp2-04 29 Explizite Typumwandlung (casting) shortVar = intVar nicht erlaubt – intVar könnte zu großen Wert enthalten. intVar = floatVar nicht erlaubt – intVar muss Nachkommaanteil "abschneiden". Cast-Ausdruck: (<type>) <ausdruck> Type von <ausdruck> und <type> beide boolean oder nicht boolean D.h. keine explizite Typwandlung in / aus boolean hs / fub - alp2-04 30 shortVar = (short)(shortVar + byteVar) und ohne Klammer? int intVar=1; intVar = (int) (intVar/2.0) automatische Typwandlung in double wegen 2.0, cast in int. Also besser 2 statt 2.0 Typischer Fehler: int i = 128; byte b = (byte) i; Wert von b? Denn sie wissen nicht, was sie tun. hs / fub - alp2-04 31 4.4 Variablen, Typen, Vereinbarung Strenge Typisierung ⇒ Literale, Variablen, Ausdrücke besitzen einen Typ Literale: automatisch - ein Literal hat (kontextabhängig) genau einem Typ Ausdrücke: abhängig vom Typ der Konstituenten doubleVar + 3 Variablen: explizit vor der ersten Nutzung vereinbaren double doubleVar; hs / fub - alp2-04 32 Variablenvereinbarung (declaration) - legt Namen der Variablen - und Typ der Variablen fest - steht (im Prinzip) an beliebiger Stelle im Programm … ; int i = j + k; - darf nur einmal im "gleichen Kontext" auftreten … ; int i = j + k; int i = a + b; nicht erlaubt (s. auch Abschnitt 4, Blöcke) <type> <identifier> {,identifier}0n ; double lowVal, highVal, meanVal; hs / fub - alp2-04 33 Warum statische Typvereinbarung? Festlegung, welche Werte Variable annehmen kann ⇒ Übersetzer kann Speicherplatz reservieren ⇒ Dokumentation (!) ⇒ Fehler verhindern float val1; double val2; val1 = 0xffff + val1; val1 = 0xffff + val2; Teurer Fehler: Absturz der ersten Ariane 5 Rakete. Aus dem Report: e) At 36.7 seconds after H0 (approx. 30 seconds after lift-off) the computer within the back-up inertial reference system, which was working on stand-by for guidance and attitude control, became inoperative. This was caused by an internal variable related to the horizontal velocity of the launcher exceeding a limit which existed in the software of this computer. (64-Bit-Zahl in 16-Bit-Zahl gewandelt) hs / fub - alp2-04 34 Wert einer frisch deklarierten Variable v ist vor der ersten Zuweisung v=… undefiniert(!); double d, e; int i; e = 1.0; d = e + i; // Übersetzungsfehler Initialisierung in Deklaration möglich <type><identifier>[=<init>]{,identifier[=init]}0n; double lowVal=0.0, highVal=0.0, meanVal; Deshalb: LocalVariableDeclarationStatement hs / fub - alp2-04 35 Konstanten sind nicht änderbare, initialisierte Variablen: final <type><identifier>=<init>{,identifier=init}0n; final PI=3.14159, E=2.71828 Beachte - <init> kann ein komplexerer Ausdruck als ein Wert sein - Namenskonvention für Konstanten: Großbuchstaben - Dokumentationscharakter von Konstanten - Übersetzer garantiert (statisch) die Invarianz von Konstanten hs / fub - alp2-04 36