Język ANSI C
Transkrypt
Język ANSI C
Katedra Elektrotechniki Teoretycznej i Informatyki sem. III - wykład 6 04.11.2010 Dr inż. M. Czyżak Język ANSI C – tablice wielowymiarowe Przekazywanie tablic w standardzie C99 Standard języka C wprowadzony w roku 1999 (C99) wprowadził istotne zmiany w stosunku do ANSI C. Nie jest on w pełni realizowany przez dostępne kompilatory, istotna część zmian wprowadzonych przez ten standard jest jednak uwzględniona w kompilatorze GNU C, który stanowi podstawę DevC++. Jedna z najbardziej istotnych zmian pojawia się przy przekazywaniu tablic wielowymiarowych do funkcji, gdzie wszystkie rozmiary przekazywanej tablicy mogą być zmiennymi, a nie stałymi ( poza pierwszym rozmiarem), jak to ma miejsce w ANSI C. W C99 rozmiar tablicy w funkcji może być zwykłą zmienną lokalną lub parametrem funkcji ( są to tzw. variable-length arrays). Język ANSI C – tablice wielowymiarowe Przekazywanie tablic w standardzie C99 Przykład. Wczytywanie i drukowanie tablic w standardzie C99.(cz.1) #include <stdio.h> void wczyt2DC99( int n, int m, int x[n][m]) // ilosc kolumn nie musi być stałą, może być podana jako parametr { int i,j; for (i=0;i<n;i++) for (j=0;j<m;j++) { printf("\n Element [%d][%d]=",i,j); scanf("%d",&x[i][j]); } } Język ANSI C – tablice wielowymiarowe Przekazywanie tablic w standardzie C99 Przykład. Wczytywanie i drukowanie tablic w standardzie C99.(cz.2) void druk2DC99( int n, int m, int x[n][m]) { int i,j; for (i=0;i<n;i++) { for (j=0;j<m;j++) printf(" %d", x[i][j]); printf("\n"); } } Język ANSI C – tablice wielowymiarowe Przekazywanie tablic w standardzie C99 Przykład. Wczytywanie i drukowanie tablic w standardzie C99.(cz.3) int main() { int a[2][2], b[3][3]; wczyt2DC99(2,2,a); wczyt2DC99(3,3,b); druk2DC99( 2,2,a); druk2DC99( 3,3,b); system("pause"); return 0; } // Tablice przekazywane do funkcji mają różne rozmiary // ilość kolumn nie musi być taka sama Wyniki działania programu Element [0][0]=1 c.d. Element [0][1]=2 1 2 3 Element [1][0]=3 4 5 6 Element [1][1]=4 7 8 9 1 2 3 4 Element [0][0]=1 Element [0][1]=2 Element [0][2]=3 Element [1][0]=4 Element [1][1]=5 Element [1][2]=6 Element [2][0]=7 Element [2][1]=8 Element [2][2]=9 Język ANSI C – operatory bitowe Język C pozwala programiście na bezpośrednie współdziałanie ze sprzętem poprzez użycie operatorów bitowych i wyrażeń bitowych. Operatory bitowe umożliwiają działanie na pojedynczych bitach. Operatory te działają wyłącznie z typami całkowitymi np. takimi jak char czy też int. Aby stosować operatory bitowe w danym systemie powinno się zgromadzić następujące informacje: - liczba bitów, które tworzą bajt, - liczba bajtów dla typów całkowitych, - system kodowania znaków (np. ASCII) - typ stosowanej reprezentacji liczb ujemnych (np. kod U2) Poniżej założymy 8-bitowy bajt i 16-bitową komórkę dla przechowywania liczb całkowitych oraz kod U2. Język ANSI C – operatory bitowe Operatory bitowe to: - ‘ ~ ‘ - bitowy operator uzupełnienia do 1, -’&’ - bitowy operator koniunkcji (iloczynu logicznego), -’ | ‘ - bitowy operator alternatywy (sumy logicznej), - ’^’ - bitowy operator różnicy symetrycznej (XOR), - ‘<<‘ - bitowy operator przesunięcia w lewo, - ‘>>’ - bitowy operator przesunięcia w prawo. Język ANSI C – operatory bitowe Bitowy operator uzupełnienia do 1, ‘ ~ ‘ Operator ten (zwany tyldą), neguje poszczególne bity swojego argumentu (zamienia zera na jedynki, a jedynki na zera). Przykład. Użycie bitowego operatora uzupełnienia do 1. #include <stdio.h> int main () { short int x,y; x=6; y=~x;// użycie operatora ~ printf(" Wartosc y=%d \n", y); system("pause"); return 0; } Język ANSI C – operatory bitowe Wartość ~x wynosi 7. Wynika to ze stosowania kodu U2 do reprezentowania liczb ujemnych. Liczba 6 ma następującą reprezentację binarną 0000 0000 0000 0110 Po negacji otrzymujemy 1111 1111 1111 1001 czyli -7 w U2. Można to łatwo sprawdzić: +7 0000 0000 0000 0111 -7 w U1 1111 1111 1111 1000, czyli po dodaniu 1, otrzymujemy 1111 1111 1111 1001) Język ANSI C – operatory bitowe Rozszerzenie znakowe ( ang. sign extension) W operacjach wykonywanych na bitach występuje problem konwersji pomiędzy różnymi formatami liczb całkowitych (np. char i short int). Przy konwersjach takich istnieje konieczność zachowania wartości konwertowanej liczby. Dla liczb ujemnych przy przechodzeniu z formatu krótszego na dłuższy, wszystkie bity starsze, które nie występowały w formacie krótszym zamieniane są na 1. Działanie, określane jako rozszerzenie znakowe, nie powoduje zmiany wartości liczby ujemnej. Język ANSI C – operatory bitowe Przykład. Rozszerzenie znakowe. Dana jest liczba - 6 w kodzie U2 umieszczona w komórce 8-bitowej 0000 0110 + 6 w U2, 1111 1001 - 6 w U1 1111 1010 - 6 w U2 Po rozszerzeniu do 16 bitów mamy 1111 1111 1111 1010 Można sprawdzić, że kod ten reprezentuje -6 w U2. + 6 0000 0000 0000 0110, - 6 w U1 1111 1111 1111 1001, -6 w U2 1111 1111 1111 1010 Język ANSI C – operatory bitowe Bitowe operatory logiczne -’&’ - bitowy operator koniunkcji (iloczynu logicznego), -’ | ‘ - bitowy operator alternatywy (sumy logicznej), - ’^’ - bitowy operator różnicy symetrycznej (XOR). Operatory te działają niezależnie na parach bitów o tej samej wadze obydwu swoich argumentów. Wyniki działania poszczególnych operatorów pokazano w tabeli. Dla dwóch danych bitów b1 i b2 otrzymujemy: b1 b2 b1&b2 b1|b2 b1^b2 0 0 0 0 0 0 1 0 1 1 1 0 0 1 1 1 1 1 1 0 Język ANSI C – operatory bitowe Przykład. Działania z zastosowaniem operatorów bitowych Dane są następujące definicje short int lanbit1=12; short int lanbit2=-35 lanbit1 0000 0000 0000 1100 lanbit2 1111 1111 1101 1101 Wykonać podane poniżej działania w programie i poprzez obliczenia na liczbach binarnych 1. ~lanbit1 -13 2. ~lanbit2 34 3.lanbit1&lanbit2 12 4.~lanbit1&lanbit2 -47 5.~(lanbit1&lanbit2) -13 6.lanbit1| lanbit2 -35 7.~(lanbit1|lanbit2) 34 8.(~lanbit1|lanbit2) -1 9. lanbit1^lanbit2 10. ~(lanbit1^lanbit2) -47 46 Język ANSI C – operatory bitowe Przykład. Wyznaczanie reprezentacji binarnej liczby 8-bitowej. #include <stdio.h> #include <conio.h> int main() { char x=12; int i,k=1, bit[8]; for (i=0;i<8;i++) { if (x&k) bit[i]=1; else bit[i]=0; k*=2; // k=k*2 } for (i=7;i>=0;i--) printf(" getch(); return 0; } %d ",bit[i]); Język ANSI C – operatory bitowe Operatory przesunięć bitowych (ang. bitshift operators) Operatory bitowe przesuwają bity swego argumentu znajdującego się po lewej stronie operatora o zadaną liczbę bitów w lewo lub w prawo. Wyrażenia z użyciem tych operatorów można zapisać następująco: E1<< E2 lub E1>>E2, gdzie E1 reprezentuje wzorzec bitowy, który ma zostać przesunięty, operator << oznacza przesunięcie w lewo, a operator >> przesunięcie w prawo, E2 określa liczbę przesunięć. Język ANSI C – operatory bitowe Jeśli nie ma nadmiaru arytmetycznego, dla operatora << przesunięcie jest równoważne mnożeniu przez 2E 2 , a na najmłodsze pozycje pierwszego argumentu wchodzą zera. Działanie operatora >> odpowiada dzieleniu całkowitemu przez 2E 2 dla typów bez znaku ( unsigned), wtedy na skrajne pozycje z lewej strony wchodzą zera. Dla typów ze znakiem, jeżeli wchodzą zera dla liczb nieujemnych, a jedynki dla liczb ujemnych mówimy o przesunięciu arytmetycznym, a jeżeli zera niezależnie od znaku liczby, to jest to tzw. przesunięcie logiczne. Język ANSI C – operatory bitowe Przykład. Użycie operatorów bitowych przesunięcia w lewo i w prawo. #include <stdio.h> #include <conio.h> int main() { int x1='A', x2='0'; int y1=3,y2=2; printf("\n %d", x1<<y1);// kod ASCII // znaku ‘A’ jest równy 65 stąd w wyniku przesunięcia otrzymujemy 520 printf("\n %d ", x2>>y2); // przesunięcie prawo o 2 odpowiada // dzieleniu całkowitemu przez 4, otrzymujemy getch(); } 12 Język ANSI C – operatory bitowe Przykład. Ustawianie określonego bitu w słowie na 1. Ustawianie bitu o numerze nrBitu na 1 x= x | 1<< nrBitu; Najpierw realizowane jest przesunięcie reprezentacji bitowej liczby 1 o nrBitu bitów w lewo, odpowiada to wstawieniu 1 na określoną pozycję, (jedynka w reprezentacji liczby 1 będąca na najmłodszej pozycji zostanie przesunięta w lewo, a z prawej strony wejdą zera), następnie wykonywana jest suma logiczna liczby x i liczby otrzymanej w wyniku działania 1<< nrBitu . Powoduje to ustawienie bitu o numerze nrBitu liczby x na 1 ( jeśli bit ten był równy 1, to suma logiczna nie spowoduje zmiany, jeżeli był on równy 0, wykonanie sumy spowoduje ustawienie go na 1). Język ANSI C – operatory bitowe Przykład. Ustawianie określonego bitu w słowie na 0. Ustawianie bitu o numerze nrBitu na 0 x= x & ~(1<<nrBitu); Działanie 1<<nrBitu opisano powyżej. Daje ono słowo, gdzie bit o wartości 1 jest na pozycji o numerze nrBitu, pozostałe bity liczby są równe zeru. Negacja tej liczby ( operator ~)daje słowo, które ma same jedynki poza zerem na pozycji nrBitu. Realizacja iloczynu logicznego tego słowa i x powoduje, że na miejsce bitu o numerze nrBitu wstawiane jest 0, a pozostałe bity nie zmieniają się. Język ANSI C – operatory bitowe Przykład. Dane jest słowo 8-bitowe. Napisać funkcję wyznaczającą wartość dziesiętną bloku n-bitowego począwszy od pozycji p ( pozycja ma wagę 2p ). int oblWartBloku (char x, int n, int p) // n – liczba bitów, p – pozycja ( pozycje numerowane od 0) { return x>>(p+1-n)& ~( ~0<<n); } Zasada działania funkcji tej jest następująca: - przesunięcie bloku n-bitowego na najmłodsze pozycje ( pozycje o wagach od n −1 1 do 2 ), jest to realizowane poprzez działanie x >> (p+1-n) - utworzenie maski wycinającej n najmłodszych bitów ze słowa 8-bitowego ( maska ta ma 1 na n najmłodszych bitach i 0 na pozostałych) - obliczenie iloczynu bitowego przesuniętego bloku n-bitowego i maski. Język ANSI C – operatory bitowe Przykład. Zastosowanie funkcji oblWartBloku. #include <stdio.h> #include <conio.h> int oblWartBloku (char x, int n, int p); int main() { int x=23; int p=4; int n=3; x=oblWartBloku(x,n,p); printf("%d",x);// x=5,z reprezentacji binarnej liczby 23 // równej (1,0,1,1,1), wyodrębniany jest // blok złożony z trzech najstarszych bitów getch(); return 0;} int oblWartBloku (char x, int n, int p) // n – liczba bitów, p – pozycja( pozycje numerowane od 0) { return x>>(p+1-n)& ~(~0<<n);}