Thema indholdsfortegnelse -- Tastaturgenvej: 'u'  Forrige tema i denne lektion -- Tastaturgenvej: 'p'  Næste slide i denne lektion -- Tastaturgenvej: 'n'Datatyper
18.  Fundamentale C datatyper

I dette kapitel ser vi primært på de fundamentale taltyper. Vi vil også se hvordan taltyperne passer ind i en lidt større sammenhæng. Endvidere vil vi også studere enumeration typer i dette kapitel.

18.1 Oversigt over typer i C18.5 Enumeration typer i andre sprog
18.2 Heltalstyper18.6 Floating point typer (1)
18.3 Enumeration types (1)18.7 Floating point typer (2)
18.4 Enumeration types (2)
 

18.1.  Oversigt over typer i C
Indhold   Op Forrige Næste   Slide Aggregerede slides    Stikord Programindeks Opgaveindeks 

Herunder giver vi et bud på en hierarkisk klassificering af typerne i C.

  • Typer i C

    • Typen void svarende til den tomme mængde uden værdier.

    • Skalar typer

      • Aritmetiske typer

        • Heltalstyper (integral types)

          • short, int, long, char

          • enumeration typer

        • Floating-point typer

          • float, double, long double

      • Pointer typer

    • Sammensatte typer (aggregerede typer).

      • Array typer

      • Record typer ( structure types)

På det øverste niveau skelner vi mellem skalartyper og sammensatte typer. Endvidere har vi også typen void på dette niveau. Typen void benyttes ofte når vi vil signalere 'ingen værdi', f.eks. når en funktion ikke tager parametre eller ikke returnerer nogen værdi.

En 'skalar' (engelsk: 'scalar') er en værdi karakteriseret udelukkende ved sin størrelse (having only magnitude). Skalartyperne består af taltyperne, som vi har meget at sige om i resten af dette kapitel. Pointertyper klassificeres også som skalartyper, og de introduceres i kapitel 22.

Vi har endnu ikke set på de sammensatte typer, arrays og records (structs). Arrays behandles mere dybdegående i kapitel 24. Records er et af de sene emner i dette kursus. Vi møder det først i kapitel 39.

 

18.2.  Heltalstyper
Indhold   Op Forrige Næste   Slide Aggregerede slides    Stikord Programindeks Opgaveindeks 

Vi har måske ikke så meget nyt at sige om heltal på dette tidspunkt. Vi vil dog pege på, at heltal findes i tre længder: int, long int og short int. Endvidere findes både signed og unsigned udgaver af disse. På jævn dansk betyder dette med og uden fortegn. Dette kan kombineres til seks forskellige typer, som vi viser i tabel 18.1. Tabellen medtager også typen char, som vi allerede i kapitel 16 indså blot repræsenteres som heltal.

Type Kort typenavn Suffix printf conv. tegn scanf conv. tegn Eksempel
signed int int intet %d eller %i %d eller %i -123
unsigned int unsigned u eller U %u %u 123U
signed long int long l eller L %li %li -123456L
unsigned long int unsigned long lu eller LU %lu %lu 123456LU
signed short int short intet %hi %hi -12
unsigned short int unsigned short intet %hu %hu 12U
char char - %c %c 'a' eller 97
Tabel 18.1    

Tabellen ovenfor viser fuld og kort typenavn samt suffix tegn så vi kan typebestemme (de fleste) talkonstanter. Vi viser også hvilke konverteringstegn der skal bruges i printf og scanf for de forskellige typer. Bemærk illustrationen af suffix tegn i den højre eksempel kolonne.

Herunder viser vi typerne fra tabel 18.1 i et konkret C program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>

int main(void) {
  int i = -123;
  unsigned ui = 123U;
  long l = -123456L;
  unsigned long ul = 123456LU;
  short s = -12;
  unsigned short us = 12U;
  char c = 97;

  printf("int: %i, unsigned: %u, long: %li, unsigned long: %lu\n",
          i, ui, l, ul);
  printf("short: %hi, unsigned short: %hu, char: %c\n",
          s, us, c);

  printf("Enter integer numbers: ");
  scanf(" %i %u %li %lu %hi %hu %c", &i, &ui, &l, &ul, &s, 
        &us, &c);

  printf("int: %i, unsigned: %u, long: %li, unsigned long: %lu\n",
          i, ui, l, ul);
  printf("short: %hi, unsigned short: %hu, char: %c\n", s, us, c);
  
  return 0;
}
Program 18.1    Et C program som illustrerer ovenstående.

I program 18.2 viser vi hvordan man finder ud af bytestørrelsen af de forskellige typer fra tabel 18.1. Outputtet fra programmet kan ses i program 18.3. Da C ikke har standardiseret taltyperne kan man opleve andre output, hvis programmet kører på en anden maskine.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* Compute the size of some fundamental types. */

#include <stdio.h>

int main(void)
{
   printf("\n");
   printf("Here are the sizes of some integral types:\n\n");

   printf("           int:%3d bytes\n", sizeof(int));
   printf("      unsigned:%3d bytes\n", sizeof(unsigned));
   printf("          long:%3d bytes\n", sizeof(long));
   printf(" unsigned long:%3d bytes\n", sizeof(unsigned long));
   printf("         short:%3d bytes\n", sizeof(short));
   printf("unsigned short:%3d bytes\n", sizeof(unsigned short));
   printf("          char:%3d byte \n", sizeof(char));

   printf("\n");
   return 0;
}
Program 18.2    Et program der 'udregner' bytestørrelsen af heltalstyperne.

1
2
3
4
5
6
7
8
9
Here are the sizes of some integral types:

           int:  4 bytes
      unsigned:  4 bytes
          long:  4 bytes
 unsigned long:  4 bytes
         short:  2 bytes
unsigned short:  2 bytes
          char:  1 byte
Program 18.3    Output fra programmet.

Endelig viser vi program 18.4 hvordan man kan få oplyst mindste og største værdier i forskellige heltalstyper. De røde konstanter i program 18.4 stammer fra header filen limits.h. Når man kører programmet på min maskine får man grænserne, som vises i program 18.5.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <limits.h>
int main(void) {

  printf("Min. int:            %12i  Max. int:           %12i\n", 
          INT_MIN, INT_MAX);

  printf("Min. unsigned int:   %12u  Max. unsigned int:  %12u\n", 
          0, UINT_MAX);

  printf("Min. long:           %12li  Max. long:          %12li\n", 
          LONG_MIN, LONG_MAX);

  printf("Min. unsigned long:  %12lu  Max. unsigned long: %12lu\n", 
          0, ULONG_MAX);

  printf("Min. short:          %12hi  Max. short:         %12hi\n",
          SHRT_MIN, SHRT_MAX);

  printf("Min. unsigned short: %12hu  Max. short:         %12hu\n",
          0, USHRT_MAX);

  return 0;
}
Program 18.4    Et program der tilgår konstanter i limits.h.

1
2
3
4
5
6
Min. int:             -2147483648  Max. int:             2147483647
Min. unsigned int:              0  Max. unsigned int:    4294967295
Min. long:            -2147483648  Max. long:            2147483647
Min. unsigned long:             0  Max. unsigned long:   4294967295
Min. short:                -32768  Max. short:                32767
Min. unsigned short:            0  Max. short:                65535
Program 18.5    Output fra programmet.

 

18.3.  Enumeration types (1)
Indhold   Op Forrige Næste   Slide Aggregerede slides    Stikord Programindeks Opgaveindeks 

Enumeration types kan anvendes i situationer, hvor vi har brug for et mindre antal navngivne heltal, som spiller bestemte og veldefinerede roller i et program.

En enumeration type er en endelig mængde af heltal som er knyttet til enumeration konstanter

En enumeration konstant (enumerator) er et navn, som på mange måder ligner en variabel

Som sædvanlig viser vi den syntaktiske komposition af nye sproglige elementer. Det viste er type erklæringer, hvor vi under betegnelsen enum tag henviser til en type med bestemte navne, der har heltalsværdier.


enum tag {name1, name2, ... namei}

enum tag {name1=expr1, name2=expr2, ... namei=expri}
Syntaks 18.1    Syntaktisk definition af to mulige former af enumeration typer i C

Lad os forstå enumeration typer gennem et eksempel, se program 18.6. Under betegnelsen enum days gemmer sig en type, som netop består af navnene sunday, monday, ... saturday. Værdien af navnet sunday er 0, værdien af monday er 1, ..., og værdien af saturday er 6.

Typen enum days bruges i program 18.6 i funktionen next_day_of. Denne funktion tager en dag som input, og returnerer den efterfølgende dag som output. Funktionen next_day_of, som vist herunder, er træls i den forstand, at vi skriver en case for hver enste ugedag. Dette er heldigvis ikke nødvendig. Vi viser en kortere version i program 19.3. Bemærk 'cyklen' der består i, at next_day_of(saturday) er lig med sunday.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
enum days {sunday, monday, tuesday, wednesday, thursday, 
           friday, saturday};

enum days  next_day_of(enum days  d){
  enum days next_day;
  switch (d){
    case sunday: next_day = monday; 
      break;
    case monday: next_day = tuesday;
      break;
    case tuesday: next_day = wednesday;
      break;
    case wednesday: next_day = thursday;
      break;
    case thursday: next_day = friday;
      break;
    case friday: next_day = saturday;
      break;
    case saturday: next_day = sunday;
      break;
  }
  return next_day;
}
Program 18.6    En enumeration type enum days og en funktion next_day_of.

I program 18.7 vises en procedure (som en void C funktion), der givet en dag som input udskriver denne dag på standard output via printf.

Implementationen af prnt_day illustrerer, at vi ikke har direkte adgang til det symbolske navn af en enumeration konstant. Hvis vi blot udskriver værdien sunday vil vi se værdien 0, og ikke "sunday". Derfor må vi lave en switch kontrolstruktur, som på baggrund af en enum days værdi udskriver en passende tekst.

Lad mig også her nævne, at man ikke kan læse enumerators med scanf. Man skal indlæse heltal, og evt. internt typekonvertere disse en enumeration værdi. Typekonvertering (type casting) bliver diskuteret i afsnit 19.2. (Under opgaveregning ved øvelserne i 5. lektion 2004 så jeg en del studerende, som havde forventet at kunne indlæse enumerators via scanf. Men den går altså ikke).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void prnt_day(enum days d){
  switch (d) {
    case sunday: printf("Sunday");
       break;
    case monday: printf("Monday");
       break;
    case tuesday: printf("Tuesday");
       break;
    case wednesday: printf("Wednesday");
       break;
    case thursday: printf("Thursday");
       break;
    case friday: printf("Friday");
       break;
    case saturday: printf("Saturday");
       break;
  }
}
Program 18.7    En funktion der udskriver det symbolske navn på en dag.

Der findes en version af programmet, hvor de to funktioner fra program 18.6 og program 18.7 er sat sammen med et hovedprogram, main. Af pladshensyn er den ikke vist her. Se Det samlede program - inklusive main på den tilhørende slide. Det direkte link er her.

I et C program bidrager anvendelse af enumeration typer primært til større læsbarhed - og lettere programforståelse

 

18.4.  Enumeration types (2)
Indhold   Op Forrige Næste   Slide Aggregerede slides    Stikord Programindeks Opgaveindeks 

I dette afsnit ser vi på et antal regler som knytter sig til enumeration typer i C. Reglerne knytter sig til syntaks 18.1. Og vi ser på endnu et eksempel.

  • Regler om betydningen af enumeration typer og konstanter

    • Enumeration konstanter har samme status som variable og må som sådan kun defineres én gang i det samme scope

    • I det første tilfælde tildeles name1 værdien 0, name2 værdien 1, etc.

    • I det andet tilfælde bestemmer programmøren hvilke heltalsværdier de enkelte enumeration konstanter tildeles

      • Der er mulighed for at to eller flere konstanter i samme enumeration type har samme værdi

I eksemplet herunder anvender vi to enumeration typer, enum grade_simple og enum grade_13. Disse afspejler karaktererne på de to skalaer bestået/ikke bestået og den danske 13 skala.

Vi ser at enumeratorerne på 13 skalaen bliver afbildet på de heltal, som karaktererne naturligt står for. Eksempelvis skriver vi nul_nul = 0 for at binde enumeratoren nul_nul til 0.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>

enum grade_simple {not_passed, passed};

enum grade_13 {nul_nul = 0, nul_tre = 3, fem = 5, seks,
               syv, otte, ni, ti, elleve, tretten = 13};

enum grade_simple convert_grade_13_to_simple_grade 
                                     (enum grade_13 g){
  enum grade_simple result; 

  if (g <= fem)
    result = not_passed;
  else 
    result = passed;
  
  return result;
}

void prnt_grade_simple(enum grade_simple g){
  switch (g) {
    case not_passed: printf("Not passed");
      break;
    case passed: printf("Passed");
      break;
  }
}  
    
int main(void){
  
  int grade_number; 
 
  printf("Enter '13 skala' grade: ");
  scanf(" %d", &grade_number);

  prnt_grade_simple(
         convert_grade_13_to_simple_grade(grade_number));
  printf("\n");

  return 0;
}
Program 18.8    Et eksempel på et program som bruger enumeration typer til karakterskalaer.

I karaktereksemplet i program 18.8 kan man klart diskutere, om introduktionen af de symbolske navne for karakterværdierne på 13 skalaen gør en nævneværdig forskel. En konsekvent anvendelse beskytter os dog mod at bruge meningsløse karakterværdier, så som -1, 4, 12 og 14.

Anvendelsen af not_passed og passed (for ikke-bestået og bestået) i stedet for 0 og 1 bidrager klart til bedre læsbarhed og forståelighed. Vi kan sige at det bringer vores program lidt tættere på virkelighedens begrebsverden.

 

18.5.  Enumeration typer i andre sprog
Indhold   Op Forrige Næste   Slide Aggregerede slides    Stikord Programindeks Opgaveindeks 

Der findes programmeringssprog, der på en mere klar og ren måde end C understøtter enumeration typer. Der findes også nyere sprog, som slet ikke har særlig understøttelse af enumeration typer.

Enumeration typer i C er anderledes end tilsvarende typer i de fleste andre programmeringssprog

  • Enumeration typer i Pascal-lignende sprog:

    • Værdien af enumeration konstanterne er nye, entydige værdier - ikke heltal

    • Ordningen af enumeration konstanterne er af betydning

      • Efterfølger og forgænger funktioner af enumeration konstanter giver mening

Java er først på det seneste begyndt at understøtte enumeration typer

Udsagnet om Javas manglende understøttelse af enumeration typer er sand for Java 1.4 og ældre versioner af sproget. Den nyeste version af Java (1.5) har en solid og rig understøttelse af enumeration typer, som går videre end de fleste andre sprog.

 

18.6.  Floating point typer (1)
Indhold   Op Forrige Næste   Slide Aggregerede slides    Stikord Programindeks Opgaveindeks 

I dette afsnit giver vi en oversigt over floating point typer i C, efter samme mønster som vi diskuterede for heltalstyper i afsnit 18.2.

Type Suffix printf conv. tegn scanf conv. tegn Eksempel
float f eller F %f %f 5.4F
double intet %f %lf 5.4
long double l eller L %Lf %Lf 5.4L
Tabel 18.2    

Bemærk lige scanf konverterings- og modifier tegnene %lf for indlæsning af double. I forhold til det tilsvarende printf konverteringstegn %f kan brug af %lf (i betydningen long float) virke underlig.

Nedenstående program viser mulighederne i tabel 18.2 i et konkret C program.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

int main(void) {

  float f = 123.456F;
  double d = 123.456;
  long double ld = 123.456L;

  printf("float: %f, double: %f, long double: %Lf\n", f, d, ld);

  printf("Enter new values: ");
  scanf(" %f %lf %Lf",&f, &d, &ld);
  printf("float: %f, double: %f, long double: %Lf\n", f, d, ld);
  
  return 0;
}
Program 18.9    Et C program som illustrerer ovenstående.

Ligesom i program 18.2 viser vi herunder hvordan vi kan bestemme bytestørrelsen af typerne float, double og long double. Det selvforklarende output fra programmet vises i program 18.11. Som omtalt tidligere er det ikke sikkert, at du får det samme output hvis du kører programmet på din computer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* Compute the size of some fundamental types. */

#include <stdio.h>

int main(void)
{
   printf("\n");
   printf("Here are the sizes of some floating types:\n\n");

   printf("      float:%3d bytes\n", sizeof(float));
   printf("     double:%3d bytes\n", sizeof(double));
   printf("long double:%3d bytes\n", sizeof(long double));

   printf("\n");
   return 0;
}
Program 18.10    Et program der 'udregner' bytestørrelsen af float typerne.

1
2
3
4
5
Here are the sizes of some floating types:

      float:  4 bytes
     double:  8 bytes
long double: 12 bytes
Program 18.11    Output fra programmet.

Ligesom i program 18.4 viser vi herunder grænserne for værdierne i typerne float, double og long double. Bemærk at der er tale om mindste og største positive tal i typerne. Output af programmet program 18.12 ses i program 18.13.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <float.h>
int main(void) {

 printf("Min. float:       %20.16e  \nMax. float:       %20.16e\n\n", 
         FLT_MIN, FLT_MAX);

 printf("Min. double:      %20.16le \nMax. double:      %20.16le\n\n", 
         DBL_MIN, DBL_MAX);

 printf("Min. long double: %26.20Le \nMax. long double: %26.20Le\n\n", 
         LDBL_MIN, LDBL_MAX);


  return 0;
}
Program 18.12    Et program der tilgår konstanter i floats.h.

1
2
3
4
5
6
7
8
Min. float:       1.1754943508222875e-38  
Max. float:       3.4028234663852886e+38

Min. double:      2.2250738585072014e-308 
Max. double:      1.7976931348623157e+308

Min. long double: 3.36210314311209350626e-4932 
Max. long double: 1.18973149535723176502e+4932
Program 18.13    Output fra programmet.

I outputtet fra program 18.12, som er vist herover, kan vi notere os at vi i printf kaldene har taget hensyn til den præcision, som understøttes af hhv. float, double og long double. Præcision er et af de emner vi ser på i næste afsnit, afsnit 18.7.

 

18.7.  Floating point typer (2)
Indhold   Op Forrige Næste   Slide Aggregerede slides    Stikord Programindeks Opgaveindeks 

Efter nu at have brugt tid og kræfter på at forstå de tre floating point typer float, double og long double vil vi nu se på notation for flydende tal, præcisionen af værdierne i de tre typer, intervallet der dækkes af typerne.

  • Notation

    • Decimal: 12345.6789

    • Eksponential: 0.1234567e-89

    • En flydende tal konstant skal enten indeholde decimal punktet eller eksponential delen (eller begge)

  • Præcision: Antallet af signifikante cifre i tallet

    • float: typisk 6 cifre

    • double: typisk 15 cifre

    • long double: typisk 20 cifre

  • Interval (range): Største og mindste mulige positive værdier

    • float: Typisk 10-38 til 1038

    • double: Typisk 10-308 til 10308

    • long double: Typisk 10-4932 til 104932

Dette afslutter vores dækning af de fundamentale heltals og floating point typer i C. Relativ til oversigten i afsnit 18.1 mangler vi at dække pointertyper og sammensatte typer. Pointertyper tager vi hul på i kapitel 22. Arrays behandles i kapitel 24, kapitel 25 og kapitel 40. Structs kommer på banen i kapitel 39.

Genereret: Onsdag 7. Juli 2010, 15:11:29
Thema indholdsfortegnelse -- Tastaturgenvej: 'u'  Forrige tema i denne lektion -- Tastaturgenvej: 'p'  Næste slide i denne lektion -- Tastaturgenvej: 'n'