Presentation laddar. Vänta.

Presentation laddar. Vänta.

Maskinnära programmering i C Föreläsning 5 Mats Brorsson.

Liknande presentationer


En presentation över ämnet: "Maskinnära programmering i C Föreläsning 5 Mats Brorsson."— Presentationens avskrift:

1 Maskinnära programmering i C Föreläsning 5 Mats Brorsson

2 IS1200 Datorteknik 2 Assemblerprogram C In- och utmatning Avbrott och "trap" Cacheminnen Trådar, synkronisering F1 F3 F4 F5 F6 F7 F8 F9 F10 F2 Ö4 Ö1 Ö2 Ö3 Ö10 Ö7 Ö8 Ö9 Ö5Ö6 lab nios2time hemlab C lab nios2io lab nios2int hemlab cache hemlab trådar tentamen

3 Hemlaboration 1: Maskinnära programmering i C Pekare, array, struct, malloc med mera Lab-PM + C-kod på webben, kompilera och kör med valfri C-kompilator Svara på alla frågor, tänk efter: "Varför?" Muntlig redovisning, 2 studenter med 1 lärare Läs Mejla till och boka Ge alltid flera alternativa tider 3

4 C jämfört med andra språk Java objekt, referenser, garbage-collection, byte-code, starkt typsystem C inga objekt, pekare, malloc/free, maskinnära, stöd för enkla datatyper Assembler inga typer alls, adresser, ingen inbyggd felkontroll 4

5 Den här föreläsningen Enkla datatyper och datarepresentation: Heltal, flyttal, Mer komplicerade datatyper (struct, array) Satser och block Pekare, pekar-aritmetik Lagring av globala och lokala variabler Stack Heap Alla exempel med handöversättning till assemblerkod använder Nios II assemblersyntax 5

6 Rekommenderad litteratur Häftet "C för den som kan Java" Kan hämtas som PDF, Tips för den som vill läsa ännu mer: Bilting, Skansholm: Vägen till C Kernighan, Ritchie: The C Programming Language Jonas Skeppstedt, Christian Söderberg, Writing efficient C code : a thorough introduction for Java programmers, 6

7 7 C för dig som kan Java main(int argc, char *argv[]) { printf(“hello, world\n”); } main(int argc, char *argv[]) { printf(“hello, world\n”); } Ditt första C-program public class Hello { public static void main(String[] args) { System.out.println("Hello World!"); } } public class Hello { public static void main(String[] args) { System.out.println("Hello World!"); } } Samma program i Java:

8 Datatyper i C Mats Brorsson KTH 8

9 Den här föreläsningen Enkla datatyper och datarepresentation: Heltal, flyttal, Mer komplicerade datatyper Uttryck, satser, block Pekare, pekar-aritmetik Lagring av globala och lokala variabler Stack Heap 9

10 10 Hexadecimala talsystemet Lär dig denna tabell utantill! Ex: = 0x68A1 Ett tal som börjar med 0x är i hexadecimal notation

11 C – inledning Syntaxen liknar Java Körningen börjar med funktionen main Inga funktioner körs om man inte anropar dem "Metoderna" kallas funktioner i C en Java-metod tillhör en klass och modifierar objekt men C har inga klasser och inga objekt 11

12 C – inledning Inga referenser, men pekare en pekare är en minnesadress med viss typkontroll kraftfullt, men lätt att göra fel Inga objekt, men poster: struct som objekt utan metoder, innehåller bara data Ingen "new", ingen garbage-collection biblioteksfunktionen malloc reserverar minne reserverat minne måste återlämnas med free 12

13 Deklaration av variabeltyp Definition av variabelvärde Typ-deklaration, så att kompilatorn kan typkontrollera programmet Definition, en deklaration som medför att kompilatorn reserverar minnesutrymme Initiering, en definition där programmeraren anger variabelns startvärde int foo = 17; 13

14 Deklaration och definition int a;/*Deklaration och definition, kompilatorn reserverar plats i minnet för variabeln a */ int b = 17;/*Definition med initiering, kompilatorn reserverar plats och lägger in startvärdet */ int b;/*Deklaration igen, anger samma typ, tillåtet! */ int b = 85;/*Ny definition, förbjudet! */ 14

15 Datatyper Grundtyper: heltal flyttal Kombinationstyper: array struct union (ej behandlat här) 15

16 Datatyper: heltal signed char short int long unsigned char unsigned short unsigned int unsigned long unsigned long long 16 minst 8 bit minst 16 bit minst 16 bit(oftast 32 bit) minst 32 bit minst 64 bit Filen limits.h ger värden för aktuell kompilator #include Exempel: INT_MAX kan ha värdet

17 Exempel: gcc för Nios II (Nios II har 32-bits adresser) char short int long long long float double 8 bit (1 byte) 16 bit (2 byte) 32 bit (4 byte) 64 bit (8 byte) 32 bit (4 byte) 64 bit (8 byte) 17 minst 8 bit minst 16 bit minst 32 bit minst 64 bit minst 32 bit

18 Exempel: gcc för amd64 (AMD64 har 64-bits adresser) char short int long long long float double 8 bit (1 byte) 16 bit (2 byte) 32 bit (4 byte) 64 bit (8 byte) 32 bit (4 byte) 64 bit (8 byte) 18 minst 8 bit minst 16 bit minst 32 bit minst 64 bit minst 32 bit

19 sizeof() Operatorn sizeof( någonting ) ersätts vid kompileringen med en konstant som är lika med storleken i bytes för den typ som någonting har Exempel long long fsize = sizeof( float ); Annat exempel double r; long long dsize = sizeof( r ); 19

20 Heltal: unsigned Hexadecimalt: 9f 50 f7 70 i C: 0x9f50f770 Tolkas som positivt heltal ( ) 20

21 Heltal: signed Hexadecimalt: 9f 50 f7 70 i C: 0x9f50f770 Teckenbiten (längst till vänster) är ettställd Tolkas som negativt heltal ( ) 21

22 Binärkod för värdet minus ett Koden för Bitvis invertering Addition av ett Och vi får kod för (Koden för -1 är alltid ”bara ettor” för alla ordlängder) 22

23 Värdet av kod för negativt tal Koden för negativt tal Bitvis invertering Addition av ett Och vi får kod Som tolkas till värdet = 91 Alltså

24 Snabbfrågor Omvandla följande decimala tal till 32-bitars tal i tvåkomplementrepresentation: Skriv talen i hexadecimalt format 24

25 Byte-ordning i minnet: little-endian, skrivning adress 0 adress 2 n (lilla änden först i minnet) little-endian byte-order

26 Byte-ordning i minnet: big-endian, läsning adress 0 adress 2 n (stora änden först i minnet) big-endian byte-order

27 Datatyper: flyttal: approximation av reella tal float double long double 27 Oftast 32 bitar (IEEE 754 )IEEE 754 Oftast 64 bitar (IEEE 754 )IEEE 754 ”Mer än double” 80 bit eller (IEEE 754 quad precision)IEEE 754 Filen float.h ger värden för aktuell kompilator #include Exempel: FLT_MAX kan ha värdet

28 Decimalt flyttal -047,120 decimalt fixtal -047,120 * 10 0 decimalt flyttal -04,7120 * 10 1 samma flyttal 28 exponent mantissa tecken

29 Binärt flyttal binärt fixtal -0101,110 * 2 0 binärt flyttal -01,01110 * 2 2 normaliserat flyttal exponent mantissa tecken

30 Binärt flyttal: float (32 bit) ,110 binärt fixtal -0101,110 * 2 0 binärt flyttal -01,01110 * 2 2 normaliserat flyttal exponenten lagras med 8 bit i excess-127-kod bara bråksiffrorna av mantissan lagras, men inte "1," tecken: 1:a för negativa tal

31 Binärt flyttal: double (64 bit) ,110 binärt fixtal -0101,110 * 2 0 binärt flyttal -01,01110 * 2 2 normaliserat flyttal exponenten lagras med 11 bit i excess-1023-kod bara bråksiffrorna av mantissan lagras, men inte "1," tecken: 1:a för negativa tal

32 Flyttal IEEE 754, 32 bitar värde = (–1) s * (1 + mantissabitar 2 ) * 2 (exp–127) s exp mantissabitar FLOAT: –17 (dec) = – (bin) = – 1,0001 * x C

33 Algoritm för omvandling till flyttal Antag ett decimalt flyttal: -4,7120 * = -0,47120 * Omvandla till -1 t * 1.M 2 * 2 (e-127) Bestäm t, M och e så att följande villkor är uppfyllda: 1.M 2 * 2 (e-127) = 4, * M 10 < 1,0 M 2 < 1.0 e är ett heltal 33

34 Varför Excess-127/1023? För då kan man använda heltalsinstruktioner för att avgöra vilket tal som är störst 34

35 Information, 32 bitar adress / värde 35 0x88 0xC1 0x00 0x88 0xC1 0x00 Little endian byte ordering FLOAT: -17 i float-format: 0x C

36 Flyttal IEEE 754, 64 bitar (-1) s * (1 + mantissabitar 2 ) * 2 (exponent-1023) s exponent mantissabitar DOUBLE: -17 (dec) = (bin) = * x C

37 Information, 64 bitar adress / värde 37 0x00 0x31 0xC0 0x00 Little endian byte ordering DOUBLE: -17 i double-format: 0x C x00 0x31 0xC0 0x00

38 Snabbfrågor Omvandla följande till 32-bitars binärkod i hexadecimalt format: Instruktionen add r12,r1,r3 Heltalet Det reella talet 1, *

39 Addition/subtraktion av flyttal Algoritm: 1. Jämför de båda talens exponenter. Skifta det minsta talets signifikand (inkl. implicit etta) till höger så att de båda talens exponenter blir lika stora 2. Addera/subtrahera signifikanderna 3. Normalisera summan 4. Om det blir exponent overflow är det aritmetiskt fel 5. Avrunda signifikanden 6. Om avrundningen medför att talet blir onormaliserat, gå till steg 3 39

40 Multiplikation av flyttal Algoritm: 1. Addera exponenterna och dra ifrån en excess 2. Multiplicera signifikanderna 3. Normalisera produkten 4. Om det blir exponent overflow är det aritmetiskt fel 5. Avrunda signifikanden 6. Om avrundningen medför att talet blir onormaliserat, gå till steg 3 7. Beräkna produktens tecken 40

41 Den här föreläsningen Enkla datatyper och datarepresentation: Heltal, flyttal, Mer komplicerade datatyper Uttryck, satser, block Pekare, pekar-aritmetik Lagring av globala och lokala variabler Stack Heap 41

42 Mer komplicerade datatyper i C Mats Brorsson KTH

43 Den här föreläsningen Enkla datatyper och datarepresentation: Heltal, flyttal, Mer komplicerade datatyper Uttryck, satser, block Pekare, pekar-aritmetik Lagring av globala och lokala variabler Stack Heap 43

44 Arrayer En array i C har alltid fix storlek Deklarationen int vektor[27]; reserverar plats för 27 heltal i en array Numreringen börjar på noll vektor[0] vektor[1]... vektor[26] /* Nu är det slut! */ 44

45 Array i minnet 45 Heltals-vektor int v[27]; v[0] = 1234; v[1] = 4711; Resultat i minnet (little-endian) 0x00 0x67 adress 0 adress 0xffffffff och här kommer v[1]: 0x800b74 adress för v[0]: 0x800b70 0x12 0x (decimalt) = 0x (hex) 1 byte 0x00 0x04 0xd (decimalt) = 0x000004d2 (hex) adress för v[2]: 0x800b78...

46 Matriser Matriser finns inte som egen typ, utan görs som arrayer av arrayer Deklarationen int matris[17][42]; ger plats för 17 rader med 42 heltal i varje rad Numreringen börjar på noll matris[0][0] matris[0][1]... matris[16][41] /* Nu är det slut! */ För dynamiskt allokerade matriser är det lite mer krångligt. 46

47 Matriser, mera detaljer Lagring i minnet matris[0][0] matris[0][1]... matris[0][41] matris[1][0] matris[1][1]... matris[1][41] matris[2][0]... och så vidare till matris[16][41] Först hela rad 0 Sedan hela rad 1 Och sen hela rad 2... Kallas radvis lagring Eng. Row major ordering Fortran har Column major ordering 47

48 Bokstäver och strängar Tecknet 'A' är ett litet heltal (65) En char använder 1 byte i minnet, och har plats för ett litet heltal (exempelvis 65) En array of char har plats för en sträng: char s[20]="Now you C a string."; Strängar slutar med en nollställd char ( ’\0’ ) som slutmarkör Exempel: "hej" == { 'h', 'e', 'j', '\0' } 48

49 Handöversättning till assembler C: char s[20]="Now you C a string."; Assembler:.data.global s s:.asciz "Now you C a string." 49

50 I minnet (exempel) 50 Exempel i C: char c = 'Q'; int x = 4711; Assembler:.data.global c c:.byte 'Q'.align 2.global x x:.word x51 0x67 adress 0 adress 0xffffffff adress för x: 0x800b64 adress för c: 0x800b62 0x12 0x00 0x800b67 0x800b66 0x800b65 Obs! Exempel på adresser (decimalt) = 0x (hex) 1 byte

51 Snabbfrågor Följande sträng finns på adress 0x80740 i minnet: char s = ”Nu ska vi C!”; Vilken adress har nästa lediga plats? 0x8074D 0x8074E 0x80750 Om strängen omedelbart följs av nedanstående definition, vilken adress läggs den på? double d; 0x8074D 0x8074E 0x80750

52 I stället för objekt: struct En struct liknar ett objekt, fast utan metoder Objektet innehåller del-variabler (oftast flera) Del-variablerna är ofta av olika typer Steg 1: deklarera en struct-typ Steg 2: deklarera en variabel av den typen Steg 3: tilldela en del-variabel ett värde 52

53 struct-exempel struct threadinfo { int sp; int id }; deklarerar en ny typ, struct threadinfo denna struct-typ innehåller två heltal struct threadinfo thisthread; deklarerar en variabel av typ struct threadinfo användning: thisthread.id = 4711; tilldelar ena heltalet i variabeln thisthread 53

54 Handöversättning till assembler C: struct threadinfo thisthread; Assembler:.data.align 2.global thisthread thisthread:.word 0.word 0 54

55 Handöversättning till assembler C: thisthread.id = 4711; Assembler:.text.align 2 movia r8,thisthread movi r9,4711 stw r9,4(r8) # id finns efter sp som tar 4 byte 55

56 I minnet (exempel) 56 De två del-variablerna i en struct ligger efter varandra i minnet Ordningen är alltid samma som i C-programmet spid 0x00 0x67 adress 0 adress 0xffffffff 0x800b94 thisthread: 0x800b90 0x00 0x12 0x00 0x800b97 0x800b96 0x800b95 0x00 0x800b91 0x800b92 0x800b93 Obs! Exempel på adresser. 1 byte

57 Kopiering av hela structen struct threadinfo { int sp; int id }; struct threadinfo thisthread; struct threadinfo otherthread; användning: otherthread = thisthread; Hela variabeln thisthread (alla delar) kopieras till variabeln otherthread Fungerar bara med struct, inte med array! 57

58 Kopiering av hela structen struct threadinfo { int sp; int id }; struct threadinfo thisthread; struct threadinfo otherthread; användning: otherthread = thisthread; Hela variabeln thisthread (alla delar) kopieras till variabeln otherthread Fungerar bara med struct, inte med array! 58 Hur många load- och storeinstruktioner behövs för att genomföra kopieringen till vänster? 1 load och 1 store 2 load och 2 store 4 load och 4 store

59 Men... finns det inga Boolean? Heltal i stället för Boolean Heltalet 0 tolkas som "falskt" Alla heltal ≠ 0 tolkas som "sant" if( heltalsuttryck ) statement1; else statement2 ; 59

60 Den här föreläsningen Enkla datatyper och datarepresentation: Heltal, flyttal, Mer komplicerade datatyper Uttryck, satser, block Pekare, pekar-aritmetik Lagring av globala och lokala variabler Stack Heap 60

61 Uttryck, Satser och Block i C Mats Brorsson KTH 61

62 Den här föreläsningen Enkla datatyper och datarepresentation: Heltal, flyttal, Mer komplicerade datatyper Uttryck, satser, block Pekare, pekar-aritmetik Lagring av globala och lokala variabler Stack Heap 62

63 If-satser 63

64 Relationsoperatorer 64

65 Repetitionsslingor 65

66 For-loopen Notera, for-loopen med följande struktur: for (i=0; i < N; i = i + 1) { … } Är detsamma som: i = 0; while (i < N) { … i = i + 1; } 66

67 Heltal i stället för Boolean if( heltalsuttryck ) statement1; else statement2 ; Exempel på heltalsuttryck: a < b Om a < b så är uttryckets värde 1, annars 0 Kan tilldelas variabler: int a_is_smaller_than_b = a < b; Motsvarande för while, for,... while( heltalsuttryck ) statement2; for( init; heltalsuttryck; update ) statement3; 67

68 68 #include int n; p(int k) { printf(“n = %d\n”, k) } int f(int a) { int b; b = a + 2; return b; } Ett komplett program /* Huvudprogram */ #define PARAMETER 10 main(){ n = f(10); p(n); } Namnet main betyder huvudprogram Genom direktivet include kan man göra sina program mer lättlästa. Parametrar till funktioner och subrutiner deklareras på samma sätt som variabler Du har möjlighet att deklarera variabler inne i en funktion/subrutin return används för att avsluta en funktion och för att tala om vad som är returvärdet #define är ett sätt att definiera konstanter.

69 Struktur C-programfil: #include #define deklaration av globala variabler funktioner Varje funktion: deklaration av namn, parametrar och returvärde en sats (statement) eller ett block vanligtvis ett block, förstås... 69

70 Stil: korthuggen programkod Utskrift av sträng int i; char s[20]; for( i = 0; s[i]; i = i + 1 ) putchar( s[i] ); Uttrycket s[i] är ett heltalsuttryck Alla heltal utom 0 räknas som "sant" Testet s[i] är sant när heltalet s[i] ≠ 0 men falskt när s[i] == 0 eftersom strängens slutmarkör är heltalet noll Svårläst och det är bättre att skriva villkoret som s[i] != NULL där NULL definierats till ’\0’. 70

71 Satser Satser kan vara if-satser etc, förstås En sats kan också bestå av ett uttryck En tilldelning är ett uttryck som ofta finns ensamt i en sats Exempel: x = 4711 är ett uttryck Sätt semikolon ; efter uttrycket så får vi en sats x = 4711; 71

72 Varning för oväntad tilldelning = betyder tilldelning == betyder test för likhet Satsen if( x == 4711 ) y = 32767; ändrar y, om x är lika med 4711 Satsen if( x = 4711 ) y = 32767; medför alltid att y ändrar värde. Varför? 72

73 Snabbfrågor Hur många repetitioner kommer följande slinga exekvera? char teckenstr = ”aaaaaaabbbbbcc”; i = 0; tecken = teckenstr[0]; while (tecken = ’a’) { // behandla tecknet a … tecken = teckenstr[i++]; } 73 1 gång 7 gånger Oändligt antal

74 Block En sats (statement) kan alltid bytas mot ett block Uttryck kan inte bytas mot block C99 och senare standarder kan blanda deklarationer och satser Block: { deklarationer först i varje block satser efter alla deklarationer } 74

75 Exempel: utskrift av sträng En kort funktion void printstring( char s[] ) { /* nytt block */ int i; /* deklarationer först i blocket */ for( i = 0; s[i]; i = i + 1 ) { putchar( s[i] ); } } nytt block omkring putchar, onödigt men mer lättläst 75

76 Bitvisa operationer i C Ettställ valda bitar med OR-operation tmp = tmp | 0x30 ; Nollställ valda bitar med AND-operation (maska fram utvalda bitar) tmp = status & 0x0F ; Invertera valda bitar med XOR-operation tmp = val ^ 0x80; 76

77 Bit Operations Assembly program (Nios-II) Skifta höger n steg (heltalsdivision med 2n) SRLI r2, r7, n # det finns även SRAI r2, r7, n Skifta vänster m steg (multiplikation med 2m) SLLI r9, r4, m # det finns ingen SLAI r9, r4, m 77 Olika hantering av teckenbiten vid högerskift SRLI skiftar in 0 SRAI skiftar in teckenbiten

78 Bit Operations C-program Skifta höger n steg (heltalsdivision med 2n) tmp = tmp >> n ; Skifta vänster m steg (multiplikation med 2m) tmp = tmp << m ; 78 Oftast implementeras högerskift som: unsigned int tmp => skifta in noll vid högerskift int tmp => skifta in teckenbiten vid högerskift

79 Bitwise operations Logical operations A & Bbitvis AND A | Bbitvis OR A ^ Bbitvis XOR ~Abitvis NOT (invertering) A && Blogisk AND A || Blogisk OR !Alogisk NOT Notera INGEN operator ^^ i C (INGEN logisk XOR) 79

80 Snabbfrågor Du har läst in ett tecken från en I/O-enhet genom att läsa in till en variabel med följande definition: int tecken; Hur ska du förbehandla det för att kunna göra följande? if (tecken == 0x41) Välj mellan tecken = tecken & 0xff; tecken = tecken && 0xff; tecken = tecken | 0xff; tecken = tecken || 0xff; 80

81 Den här föreläsningen Enkla datatyper och datarepresentation: Heltal, flyttal, Mer komplicerade datatyper Uttryck, satser, block Pekare, pekar-aritmetik Lagring av globala och lokala variabler Stack Heap 81

82 Pekare och pekararitmetik i C Mats Brorsson KTH 82

83 Den här föreläsningen Enkla datatyper och datarepresentation: Heltal, flyttal, Mer komplicerade datatyper Uttryck, satser, block Pekare, pekar-aritmetik Lagring av globala och lokala variabler Stack Heap 83

84 Pekare En pekare är en sorts variabel Pekaren innehåller en adress Exempel int valle; int * pelle; pelle = &valle; *pelle = 17; 84 0x800b98 17 adress 0 adress 0xffffffff valles adress 0x800b98 pelles adress 0x800b60 4 byte Obs! Bara exempel på adresser.

85 Pekar-operatorer Tilldela pekaren en adress pelle = &valle; Operatorn & (med en variabel som argument) betyder "minnesadressen till" variabeln Varning: genom att ta adressen till en variabel förindrar man att kompilatorn kan allokera den i ett register Följ pekaren och skriv *pelle = 17; Operatorn * (med en pekare som argument) betyder "pekarens innehåll är adressen till en plats i minnet där läsning/skrivning ska göras" 85

86 int valle; int * pelle; Assembler.data.align 2.global valle valle:.word 0.data.align 2.global pelle pelle:.word 0 86 adress 0 adress 0xffffffff valles adress 0x800b98 pelles adress 0x800b60 4 byte Exempel på handöversättning

87 Handöversättning till assembler C pelle = &valle; Assembler.text.align 2 movia r8,valle movia r9,pelle stw r8,0(r9) 87 adress 0 adress 0xffffffff valles adress 0x800b98 pelles adress 0x800b60 4 byte

88 Steg för steg: pelle = &valle; Assembler.text.align 2 movia r8,valle 88 adress 0 adress 0xffffffff valles adress 0x800b98 pelles adress 0x800b60 4 byte r8 0x800b98 r9

89 Steg för steg: pelle = &valle; Assembler.text.align 2 movia r8,valle movia r9,pelle 89 adress 0 adress 0xffffffff valles adress 0x800b98 pelles adress 0x800b60 4 byte r8 0x800b98 r9 0x800b60

90 Steg för steg: pelle = &valle; Assembler.text.align 2 movia r8,valle movia r9,pelle stw r8,0(r9) 90 0x800b98 adress 0 adress 0xffffffff valles adress 0x800b98 pelles adress 0x800b60 4 byte r8 0x800b98 r9 0x800b60

91 Handöversättning till assembler C *pelle = 17; Assembler.text.align 2 movia r8,17 movia r9,pelle ldw r10,0(r9) stw r8,0(r10) 91 0x800b98 adress 0 adress 0xffffffff valles adress 0x800b98 pelles adress 0x800b60 4 byte

92 Steg för steg: *pelle = 17; Assembler:.text.align x800b98 adress 0 adress 0xffffffff valles adress 0x800b98 pelles adress 0x800b60 4 byte r8 r9 r10

93 Steg för steg: *pelle = 17; Assembler:.text.align 2 movia r8, x800b98 adress 0 adress 0xffffffff valles adress 0x800b98 pelles adress 0x800b60 4 byte r8 17 r9 r10

94 Steg för steg: *pelle = 17; Assembler:.text.align 2 movia r8,17 movia r9,pelle 94 0x800b98 adress 0 adress 0xffffffff valles adress 0x800b98 pelles adress 0x800b60 4 byte r8 17 r9 0x800b60 r10

95 Steg för steg: *pelle = 17; Assembler:.text.align 2 movia r8,17 movia r9,pelle ldw r10,0(r9) 95 0x800b98 adress 0 adress 0xffffffff valles adress 0x800b98 pelles adress 0x800b60 4 byte r8 17 r9 0x800b60 r10 0x800b98

96 Steg för steg: *pelle = 17; Assembler:.text.align 2 movia r8,17 movia r9,pelle ldw r10,0(r9) stw r8,0(r10) 96 0x800b98 17 adress 0 adress 0xffffffff valles adress 0x800b98 pelles adress 0x800b60 4 byte r8 17 r9 0x800b60 r10 0x800b98

97 Pekartyper Exempel: pointer to char pointer to int pointer to double pointer to struct h men struct h ska förstås vara definierad tidigare 97 char * cp; int * ip; double * dp; struct h * hp;

98 Storlekar Hur stor är pekarvariabeln? struct h { int v1; int v2; char s[20]; }; struct h * hp; printf( "hp: %ld \n", sizeof( hp ) ); En adress är alltid lika stor (som andra adresser) Hur stor är den typ som pekarvariabeln är deklarerad att peka på? printf( "*hp: %ld \n", sizeof( *hp ) ); Väldigt olika för olika typer 98

99 Test: sizeof( hp ) och sizeof( *hp ) C-program #include int main() { struct h { int v1; int v2; char s[20]; }; struct h * hp; printf( "hp: %ld \n", sizeof( hp ) ); printf( "*hp: %ld \n", sizeof( *hp ) ); return( 0 ); } Utmatning hp: 8 *hp: 28 99

100 Void Typen void är speciell, betyder "inget värde" En funktion utan returvärde har returtypen void void puttime( int mytime ) En funktion utan parametrar kan skrivas med void (eller utlämnas) int getchar( void ) En voidpekare (pointer to void) får peka på objekt av vilken typ som helst En voidpekare får inte följas/avrefereras 100

101 Voidpekare int tal; int * ip; void * vp; vp = (void *) &tal; /* voidpekaren får adressen till tal */ (void *) kallas ”type cast” och gör att man kan göra om typer GÖR DETTA ENBART NÄR DU VET EXAKT VAD SOM HÄNDER! *vp = 17; /* avreferera voidpekare med tilldelning av heltal, fel! */ ip = (int *) vp; /* läs vp med type cast */ *ip = 17; /* avreferera int-pekare, går bra */ *( (int *) vp ) = 4711; /* krångligt men korrekt */ 101

102 Snabbfrågor Antag följande definitioner: int *p; int i; int k; i = 42; k = i; p = &i; Vilka av följande kommer ändra på variabel i till 75? k = 75; *k = 75; p = 75; *p = 75; Två eller fler av svaren ovan kommer ändra i till

103 byte-vektor, textsträng, char [ ] En vektor av bytes char text[14] = "Hello, world!"; /* 14 bytes, kom ihåg nolltecknet på slutet! */ med index 0 – 13 &text[0] – adress till första tecknet, pointer to char text – också adress till första tecknet, pointer to char 103

104 bytevektor, pointer to char char text[14] = "Hello, world!"; /* 14 bytes, kom ihåg nolltecknet på slutet! */ char * cp1 = &text[0]; *cp1 = 'Y'; Nu är strängen "Yello, world!" char * cp2 = text; *cp2 = 'C'; Nu är strängen "Cello, world!" 104

105 Lagring av textsträng, char [ ] 105 C-kod: char text[] = ”Hello, world!”; Assemblerkod:.data text:.asciz ”Hello World!” adress 0 adress 0xffffffff text[13] text[0] 1 byte 'H' 'e' 'l' 'o' ',' ' 'w' 'o' 'r' 'l' 'd' 'l' '!' 0x00

106 Pekar-aritmetik: char char text[14] = "Hello, world!"; /* 14 bytes, kom ihåg nolltecknet på slutet! */ char * cp1 = &text[0]; cp1 = cp1 + 1; Nu är cp1 adressen till 'e' *cp1 = 'u'; Nu är strängen "Hullo, world!" 106

107 Pekar-aritmetik: int (överkurs) int v[27]; v[0] = 1234; int * ip = &v[0]; ip = ip + 1; *ip = 65535; Ökas med 1 i C-kod, men ökas med 4 i assembler! Skalning med sizeof(int) 107 0x00 0xff adress 0 adress 0xffffffff och här kommer v[1]: 0x800b74 adress för v[0]: 0x800b70 0xff 0x (decimalt) = 0x0000ffff (hex) 1 byte 0x00 0x04 0xd (decimalt) = 0x000004d2 (hex) adress för v[2]: 0x800b78...

108 memcpy i C-kod (block data transfer) void memcpy (void * dst, void * src, int num) { int i; char * localdst = (char *) dst; char * localsrc = (char *) src; for (i=0; i

109 memcpy i C-kod (block data transfer) void memcpy (void * dst, void * src, int num) { int i; char * localdst = (char *) dst; char * localsrc = (char *) src; for (i=0; i

110 Matriskopiering i C #define ROWSIZ 17 #define COLSIZ 27 int enamatrisen[ROWSIZ][COLSIZ]; int andramatrisen[ROWSIZ][COLSIZ]; void matcpy (int* dst, int* src) { int i, j; for (i=0; i

111 Omvänd ordning på rader och kolumner: blir det någon skillnad? #define ROWSIZ 17 #define COLSIZ 27 int enamatrisen[ROWSIZ][COLSIZ]; int andramatrisen[ROWSIZ][COLSIZ]; void matcpy (int* dst, int* src) { int i, j; for (j=0; j

112 Omvänd ordning på rader och kolumner Adressberäkning För att hitta dst[i][j] ska datorn beräkna (i * ROWSIZ + j) * elementstorleken och addera det till startadressen för matrisen Används matrisen radvis, i samma ordning som lagringen, så kan kompilatorn ta bort adressberäkningen Adderar elementstorleken sizeof(int) till adresserna inför varje ny iteration 112

113 Pekare för att komma åt I/O-enheter I/O-enheter är avbildade i adressrymden precis som variabler. De är speciella eftersom t.ex. en In-enhet kan ändra värde mellan två läsningar En Ut-enhet kan ta emot flera värden efter varandra Exempel: Ut-enhet som tänder/släcker lysdioder (LEDs) beroende på bitvärde In-enhet där man kan se hur ett antal strömbrytare är satta 113

114 Enkel I/O-programmering i C #define LED 0x4408// fiktiv adress #define SWITCH 0x440C// också fiktiv adress unsigned int *switches = SWITCH; unsigned int *leds = LED; int swtch_temp; // Läs inporten och mata ut till LED swtch_temp = *switches; // läs switch swtch_temp = 0x3ff; // 18 minst signifikanta *leds = swtch_tmp; // tänd/släck leds 114

115 Snabbfrågor Antag följande kod: unsigned char *inport = PORT_ADDRESS; while ((*inport & 0x80) && (i<100)) { while (!(*inport & 0x80)) ; tecken[i++] = (*inport & 0x7f); } Hur många iterationer exekverar den yttre slingan? 0 gånger, villkoret kan aldrig vara sant 1 gång, den fastnar i den inre slingan Det går inte att fastställa men max 100 gånger 100 gånger 115

116 Den här föreläsningen Enkla datatyper och datarepresentation: Heltal, flyttal, Mer komplicerade datatyper Uttryck, satser, block Pekare, pekar-aritmetik Lagring av globala och lokala variabler Stack Heap 116

117 Lagring av globala och lokala variabler Mats Brorsson KTH

118 Den här föreläsningen Enkla datatyper och datarepresentation: Heltal, flyttal, Mer komplicerade datatyper Uttryck, satser, block Pekare, pekar-aritmetik Lagring av globala och lokala variabler Stack Heap 118

119 Variabler i minnet (register) Viktiga aspekter att ta med Allokering av minne vid kompilering at compile-time Allokering av minne vid exekvering at run-time global / lokal variabel code-area, data-area, heap-area, stack-area push och pop för stacken malloc() och free() för heapen 119

120 Statisk allokering av minne at compile time Vid kompilering+länkning reserveras minne för Programkoden – text Globala data initialized (.data) uninitialized (.bss) (Block Started by Symbol) Heap-area Stack-area 120

121 Minnesuppdelning 121 program - kod data bss heap stack adress 0 program - kod heap stack adress 2 n -1 Exempel 1Exempel 2 data bss PC SP

122 Programstart 122 header program- kod data symboltabell program- kod heap data bss kopiering vid programstart körbar filminne

123 Dynamisk allokering av minne at execution/run -time Vid exekvering allokeras minne på stack och används för Parametrar vid funktionsanrop Returadress vid funktionsanrop Lokala variabler i anropad funktion Skydd av register vid registerbrist (r16 – r23) 123

124 Dynamisk allokering av minne at execution/run time Vid exekvering allokeras minne på heap och används för Dynamiska data-strukturer 124

125 malloc() och free() dynamisk allokering på heap /* Tänkbar bakgrund*/ struct elephant { char[13] name;/* 16 bytes ? ! */ int weight;/* 4 bytes */ double area; /* 8 bytes */ } ; struct elephant dumbo; 125

126 malloc() och free() dynamisk allokering på heap struct elephant * ep;... ep = (struct elephant *) malloc (sizeof (struct elephant));... * ep = dumbo;... free (ep); /* ep MÅSTE ha samma värde som från malloc */ 126

127 Snabbfrågor Vilken eller vilka av följande allokeringar gör vad du troligen vill givet deklarationen? struct node { int key; struct node * next; }; struct node * x = malloc(sizeof(*x)); struct node * x = malloc(sizeof(* struct node )); struct node * x = malloc(sizeof(struct node));

128 Lokala variabler Deklareras i ett block Tillgänglig endast i samma block som deklarationen Startvärdet skrivs när funktionen anropats Anger man inget startvärde så blir startvärdet odefinierat Exempel #include int main() { int g = 4711; printf( "g: %d \n", g ); g = 17; printf( "g: %d \n", g ); return( 0 ); } Utmatning g: 4711 g:

129 Globala variabler Deklareras utanför alla funktioner Tillgängliga i alla funktioner Startvärde lagras i körbar fil ("exe-filen") Anger man inget startvärde så blir startvärdet noll Utnyttja inte detta! Svårläst kod Exempel #include int g = 4711; int main() { printf( "g: %d \n", g ); g = 17; printf( "g: %d \n", g ); return( 0 ); } Utmatning g: 4711 g:

130 Deklaration av global variabel: kompilering på riktigt 130 C #include int g = 4711; /* global */ int main() { printf( "g: %d \n", g ); g = 17; printf( "g: %d \n", g ); return( 0 ); } Förväntad kompilering.global g.data.align 2 g:.word 4711 Verklig kompilering.global 2.type g, 4 g:.long 4711 Ger mer hjälpsam info till länkningen

131 Minnesdisposition (minnes-karta) Programkod.text Globala data.data (indelad i fler delar) Dynamiska data Stack 131 program - kod data heap stack adress 0 adress 2 n -1 Unix v7 PC SP

132 Globala variabler: hur funkar det? Lagras i data-arean Global Pointer GP GP innehåller adress till första globala variabeln Exempel #include int valle; int * pelle; int main() { pelle = &valle; *pelle = 17; printf( "valle: %d \n", valle ); return( 0 ); } 132

133 Handöversättning till assembler 133 int valle; int * pelle; Assembler.data.align 2.global valle valle:.word 0.data.align 2.global pelle pelle:.word 0 adress 0 adress 0xffffffff valles adress 0x800b98 pelles adress 0x800b60 4 byte REPRIS

134 Handöversättning till assembler int valle; int * pelle; Assembler.data.align 2.global valle valle:.word 0.data.align 2.global pelle pelle:.word adress 0 adress 0xffffffff valles adress 0x800b94 pelles adress 0x800b98 4 byte Obs! Realistiska exempel på adresser. gp innehåller 0x800b90 r26/gp 0x800b90

135 Handöversättning till assembler int main() { Assembler.text.align 2.global main main: 135 adress 0 adress 0xffffffff valles adress 0x800b94 pelles adress 0x800b98 4 byte gp innehåller 0x800b90 gp 0x800b90

136 Handöversättning till assembler C pelle = &valle; Assembler addi r2,gp,4 stwr2,8(gp) 136 adress 0 adress 0xffffffff valles adress 0x800b94 pelles adress 0x800b98 4 byte gp innehåller 0x800b90 gp 0x800b90

137 Steg för steg 137 pelle = &valle; Assembler addi r2,gp,4 Resultat: r2 = 0x800b94 Assembler stwr2,8(gp) Skriver 0x800b94 till det minnesord som har adress gp+8 0x800b94 adress 0 adress 0xffffffff valles adress 0x800b94 pelles adress 0x800b98 4 byte gp innehåller 0x800b90 gp 0x800b90

138 Kompilering på riktigt Handöversättningen av pelle = &valle är addi r2,gp,4 stwr2,8(gp) Kompilering ger addi r2, gp, %gprel(valle) Om valles adress är gp+4 så översätts %gprel(valle) till 4 stw r2, %gprel(pelle)(gp) Är pelles adress gp+8 så är %gprel(pelle) 8 och denna rad blir stw r2,8(gp) 138

139 Handöversättning till assembler 139 C *pelle = 17; Assembler ldwr3,8(gp) movi r2,17 stw r2,0(r3) 0x800b94 adress 0 adress 0xffffffff valles adress 0x800b94 pelles adress 0x800b98 4 byte gp innehåller 0x800b90 gp 0x800b90

140 140 Steg för steg *pelle = 17; (1) Läs pekarens värde (innehållet i pelle) ldwr3,8(gp) (2) Lägg 17 i ett register movi r2,17 (3) Skriv (följ pekaren) stw r2,0(r3) 0x800b94 17 adress 0 adress 0xffffffff 4 byte r2 17 0x800b94 (2) valles adress 0x800b94 gp innehåller 0x800b90 r3 (1) (3) pelles adress 0x800b98 r26 0x800b90

141 Kompilering på riktigt Handöversättningen av *pelle = 17 är ldw r3,8(gp) movi r2,17 stwr2,0(r3) Kompilering ger ldw r3, %gprel(pelle)(gp) movi r2, 17 stw r2, 0(r3) %gprel(pelle) är 8 i vårt exempel 141

142 Testkod med många parametrar Börjar här #include int fun(int,int,int,int,int,int); int main() { int r; r = fun( 1, 2, 3, 4, 5, 6 ); printf( "result = %d\n", r ); return( 0 ); } Funktionen fun finns i en annan fil 142


Ladda ner ppt "Maskinnära programmering i C Föreläsning 5 Mats Brorsson."

Liknande presentationer


Google-annonser