C für PICs: Variablen
        
      
    
    
    zurück
        zu C für PICs , C-Compiler , PIC-Prozessoren , Elektronik , Homepage
    
    C für PICs
      
      Grundlagen von C
      Variablen
          Funktionen
          Operationen
        Programmablaufsteuerung
      Arrays und Strings
      Pointer
      Strukturierte Typen
        PIC-spezifisches
    
    
        zurück zu C für PICs 
    
    
    Variablen
    
    Eine Variable ist ein Stückchen Arbeitsspeicher des PIC, in dem
    man einen Wert (z.B. eine Zahl) speichern kann. Jede Variable
    bekommt
    vom Programmierer einen Namen und einen Typ ("Größe" des
    RAM-Bereichs). Mit Variablen kann man rechnen, und ihr Wert kann
    durch
    Operationen im Programm verändert werden, woher wohl auch der Name
    stammt.
    
    
Datentypen
    
    Eine Speicherzelle des PIC ist 1 Byte (8 Bit) groß. Damit
    lässt sich eine Zahl mit einem Wert von 0 bis 255 speichern. Will
    man mit anderen Werten (größere Zahlen, negative Zahlen,
    Fließkommazahlen, Textzeichen) arbeiten, so muss der Zahlenwert
    im Byte anders interpretiert werden oder es müssen sogar mehrere
    Bytes zu einer Variablen zusammengefasst werden. Man bezeichnet das
    dann als Datentyp einer Variable.
    Wenn man in der Mathematik für eine Formel eine Variable namens
    "a" einführt, dann kann man "a" mit allen möglichen
    Zahlenwerten belegen. Will man im Computerprogramm eine Variable "a"
    einführen (deklarieren), dann muss man dem Compiler sofort
    mitteilen, welchen Typ diese Variable haben soll, damit die richtige
    Menge Speicherplatz reserviert wird, und die Bits in diesem
    Speicherplatz später automatisch richtig interpretiert werden.
    
    In C unterscheidet man fünf grundlegende Datentypen, die durch
    vier Zusatzbezeichnungen (Modifier) noch abgewandelt werden können.
    
    
      
        
          Grundtyp 
           | 
          Bedeutung 
           | 
          Bits 
           | 
          Schlüsselwort 
           | 
        
        
          character 
           | 
          ein druckbares Zeichen wie
            z.B.
            ein einzelner Buchstabe 
           | 
          8 
           | 
          char 
           | 
        
        
          integer 
           | 
          eine ganzzahlige Zahl 
           | 
          16 
           | 
          int 
           | 
        
        
          float 
           | 
          eine Fließkommazahl 
           | 
          32 
           | 
          float 
           | 
        
        
          | double | 
          eine Fließkommazahl
            doppelter Genauigkeit 
           | 
          64 (in C18 nur 32 bit) 
           | 
          double | 
        
        
          void 
           | 
          steht für "nichts", also
            für keinen Wert 
           | 
          - 
           | 
          void | 
        
      
    
    
    Die Datengrundtypen können durch das Voranstellen eines der
    folgenden Modifier abgewandelt werden:
    
    
      
        
          Modifier 
           | 
          Bedeutung 
           | 
          Schlüsselwort 
           | 
        
        
          signed 
           | 
          Zahl kann positiv oder
            negativ
            sein 
           | 
          signed  | 
        
        
          unsigned 
           | 
          Zahl ist immer positiv 
           | 
          unsigned  | 
        
        
          long 
           | 
          "lange" Variante des
            Grundtyps
            mit mehr Bits 
           | 
          long  | 
        
        
          | short | 
          "kurze" Variante des
            Grundtyps
            mit weniger Bits  | 
          short  | 
        
      
    
    
    Zusätzlich zu diesen Grundtypen können weitere Typen
    definiert werden. Welche Typen der Compiler schon kennt, und wie er
    diese Typenbezeichnungen interpretiert, ist leider etwas vom
    jeweiligen
    Compiler abhängig. 
    
      - So sollte eigentlich "integer" der Datenwortbreite des
        Prozessors
        entsprechen und ist so auf jedem Rechner etwas anders definiert.
        Allerdings ist im C18-Compiler der integer-Typ 16 Bit lang,
        obwohl
        dieser PIC ein 8-Bit Datenbus hat. 
 
      - Der double Typ ist normalerweise 64 Bit lang. In C18 ist aber
        double mit float identisch, also nur 32 Bit lang.
 
      - In C18 gibt es zusätzliche 24 Bit integer Typen mit dem
        originellen Modifier "short long".
 
    
    Ein Blick in die Dokumentation lohnt also.
    
    Nachfolgend einige Typendefinitionen des C18-Compilers und ihr
    jeweiliger Wertebereich:
    
    
      
        
          Typ 
           | 
          Anzahl der
            Bits 
           | 
          Wertebereich 
           | 
        
        
          bit 
           | 
          1 
           | 
          0 bis 1 
           | 
        
        
          char 
           | 
          8 
           | 
          -128 bis 127 
           | 
        
        
          unsigned char 
           | 
          8 
           | 
          0 bis 255 
           | 
        
        
          signed char 
           | 
          8 
           | 
          -128 bis 127 
           | 
        
        
          int 
           | 
          16 
           | 
          -32768 bis 32767 
           | 
        
        
          unsigned int 
           | 
          16 
           | 
          0 bis 65535 
           | 
        
        
          short int 
           | 
          16 
           | 
          -32768 bis 32767 | 
        
        
          | unsigned short int  | 
          16 
           | 
          0 bis 65535 | 
        
        
          short long 
           | 
          24 
           | 
          -8 388 608 bis 8 388 607 
           | 
        
        
          unsigned short long 
           | 
          24 
           | 
          0 bis 16 777 215 
           | 
        
        
          long int 
           | 
          32 
           | 
          -2 147 483 648 bis 2 147 483
            647 
           | 
        
        
          unsigned long int 
           | 
          32 
           | 
          0 bis 4 294 967 295 
           | 
        
        
          float 
           | 
          32 
           | 
          1.17E-38 bis 6.80E+38 
           | 
        
        
          double 
           | 
          32  | 
          1.17E-38 bis 6.80E+38  | 
        
      
    
    
    Die Wertangaben bei den float-Typen sind eine abgekürzte
    Exponentialschreibweise. So steht "6.80E+38" für den Wert 6,8 x 1038.
    Das ist dann also etwa 680000000000000000000000000000000000000. Die
    Floattypen eignen sich dadurch für sehr große und sehr
    kleine Werte.
    
    Man erkennt, dass int eigentlich
    schon
    short signed int ist.
    Auch kann man sehen, dass sowohl long
      int wie unsigned long int
    als auch float jeweils 32
    Bit
    lang sind. Sie repräsentieren aber andere Wertebereiche. Das
    gleiche 32-Bit-Muster in entspricht also einer ganz anderen Zahl, je
    nachdem, welchen Typ diese 32-Bit-Zahl darstellt. Deshalb ist es
    für den Compiler so wichtig, dass gleich bei der Deklaration einer
    Variable der Typ festgelegt wird.
    
    Wird unsigned, short oder long ohne nachfolgenden
    Grundtyp
    verwendet, dann geht der Compiler davon aus, das der
    integer-Grundtyp
    verwendet werden soll. In der Praxis kann man also long anstelle von long int schreiben.
    
    
    Variablen-Deklaration
    
    Benötigt man eine Variable, dann deklariert man sie, indem man den
    Typ gefolgt vom Variablennamen schreibt:
    
    Typ Variablenname;
      
    
    Der Typ kann ein Modifier mit einem Grundtyp, oder der Bezeichner
    eines
    extra definierten Typs sein. Ein Beispiel wäre:
    
    int alfa;
      
    
    Der Compiler reserviert nun den für eine Variable dieses Typs
    (integer) nötigen Speicherplatz (2 Byte), und kennt ab sofort
    diese Variable mit dem Namen "alfa". 
    
    Man kann auch mehrere Variablen des gleichen Typs definieren, indem
    man
    eine Liste der Variablennamen verwendet:
    
    int alfa, beta,
        gamma;
    
    
    Wird eine Variable innerhalb einer Funktion definiert, dann wird ihr
    Speicherplatz am Ende der Funktion wieder freigegeben, und der
    Compiler
    vergisst dann diese Variable. So eine Variable ist eine lokale
    Variable. Sie ist außerhalb ihrer Funktion (also im Hauptprogramm
    oder in anderen Funktionen) unbekannt. Aus diesem Grunde können
    lokale Variablen in unterschiedlichen Funktionen auch den gleichen
    Namen haben, ohne das der Compiler "durcheinander kommt". (Der C18
    erwartet die Deklaration lokaler Variablen immer am Anfang der
    Funktion
    - also vor der ersten Operation. Werden mitten in der Funktion noch
    weitere lokale Variablen deklariert, meldet C18 einen Fehler.)
    
    Eine Variable, die außerhalb von Funktionen definiert wird ist
    eine globale Variable. Auf sie kann innerhalb jeder Funktion des
    Programms zugegriffen werden.
    
    
    
    Wertzuweisung
        
      Mit der Deklaration einer Variable wurde ihr
    Speicherplatz zugewiesen. Der (numerische) Wert dieser Variable wird
    durch das Bitmuster in diesem Speicherplatz bestimmt. Das ist aber
    noch
    ein zufällig dort stehender Wert. 
    Um nun der Variable einen Wert zuzuweisen (die Speicherzellen mit
    einem
    definierten Wert zu beschreiben) dient der "=" Operator.
    
    Variablenname =
        Wert;
      
    
    Der Wert kann einfach eine Zahl sein, aber auch eine Berechnung,
    eine
    Variable des gleichen Typs oder eine Funktion kann einen Wert
    liefern.
    
    alfa = 100;
        beta = 100 + 25;
        gamma = alfa + beta;
        
       
    Man muss darauf achten, dass der Wert auch dem Typ der Variablen
    entspricht. In einer Integer-Variablen wie alfa kann man
    keinen
    Fließkommawert speichern. Der Wert "100" ist in Ordnung, aber
    "5.6" oder auch "100.0" sind nicht zulässig. 
    
    
    
    Typumwandlung
    
    In C ist es zulässig, Variablen verschiedener Typen in einem
    Ausdruck "miteinander  zu verrechnen". Damit das funktioniert,
    müssen "kleine" Typen zu "größeren" Typen erweitert
    werden. 
    
    int Iwert;
      float
        Fwert;
      Iwert =
        5;
      Fwert =
        2.2;
      double
        Dwert =
        Iwert + Fwert;
    
    
    Im Beispiel werden eine int-Variable (Iwert) und eine float-Variable
    (Fwert) miteinander addiert. Dazu ist es nötig, dass erst einmal
    beide Variablen in den gleichen Typ überführt werden. Da der
    Definitionsbereich (Wertebereich) von float
    viel größer ist als der von int,
    kann man nicht jeden float-Wert
    in einen int-Wert wandeln.
    Andersherum kann
    aber jeder int-Wert in
    einer float-Variable
    gespeichert werden.
    Deshalb wird hier Iwert in float gewandelt.
Nun
    können die beiden float-Werte
    addiert
    werden.
    
    Das Ergebnis der Addition ist ein float-Wert.
Da
der
    aber in einer double-Variablen
abgespeichert
    werden soll, muss er schließlich noch in double umgewandelt werden.
    
    Diese Umwandlungen erfolgen automatisch, und führen nicht dazu,
    dass die deklarierten Typen von Iwert oder Fwert verändert werden.
    Es wird innerhalb des Ausdruckst sozusagen mit Kopien der
    Variablenwerte gearbeitet, und nur diese Kopien werden erweitert.
    
    Typerweiterungen erfolgen immer in folgender Richtung:
    
    char -> unsigned
        int -> long int -> unsigned long int -> float ->
        double
        -> long double
    
    
    
    Schauen wir uns noch mal ein weiteres Beispiel an:
    
    int alfa
      char
        beta;
      float
        gamma;
      alfa = 5;
      beta = 2;
      gamma =
        alfa /
        beta;
      
    
    Es soll alfa durch beta geteilt werden. Dazu
    müssten alfa und beta vom selben Typ sein, was
    sie
    aber noch nicht sind. Es muss der beta-Wert
auf
den
    int Typ erweitert werden.
    Danach sind beide Operanden vom gleichen Typ (int) und die Division wird
    vorgenommen. Da int ein
    Ganzzahltyp ist, ist auch das Ergebnis ganzzahlig, in diesem Falle
    also
    2 (und nicht etwa 2.5). Dieses Ergebnis soll nun in gamma abgespeichert werden. Da
    gamma vom float Typ ist, wird auch das
    Rechenergebnis in float gewandelt.
Aus
2
    wird dadurch 2.0.
    
    Ein numerisch exaktes Ergebnis wäre natürlich "2.5", aber
    dafür wäre eine Fließkommadivision nötig gewesen.
    Die lässt sich aber einfach erzwingen, indem man in der Division
    wenigstens einen float-Operanden
verwendet.
Man
    könnte als Typ für alfa
    oder beta den float-Typ verwenden, oder man
    macht
    es so:
    
    int alfa
      char
        beta;
      float
        gamma;
      alfa = 5;
      beta = 2;
        gamma = alfa;
      gamma
        =
        gamma / beta;
      
    
    Das ist natürlich etwas umständlich, weshalb man in C
    dafür eine "Abkürzung" geschaffen hat. Wenn man vor dem
    Variablennamen einen in Klammern gesetzten Typbezeichner schreibt,
    dann
    wird der Compiler angewiesen, den Typ der Variable auf den
    angegebenen
    Typ zu wandeln. Das kann dann so aussehen:
    
    int alfa
      char
        beta;
      float
        gamma;
      alfa = 5;
      beta = 2;
      gamma =
        (float)alfa / beta;
    
    
    Da nun alfa auf float erweitert wird, muss auch
    beta in float gewandelt werden.
    Konsequenterweise wird nun eine Fließkommadivision
    durchgeführt, die das gewünschte Ergebnis "2.5" liefert.
    
    Ich betone noch einmal, dass der eigentliche Typ der Variablen nicht
    verändert wird. Eine einmal definierte char-Variable bleibt immer char, auch wenn sie in diversen
    Ausdrücken mit Typenwandlungen in int
    und float traktiert wurde.
    Die Erweiterungen erfolgen immer nur an Kopien der Variablenwerte.
    
    
-->
      weiter
      zu Funktionen
    
    
    
      zurück
          zu C für PICs , C-Compiler , PIC-Prozessoren , Elektronik , Homepage
      
    
     
    
    Autor: sprut 
    erstellt: 01.10.2007
    letzte Änderung: 26.04.2015