Bitowe operatory
dla wielkości typu unsigned zwolnione bity zawsze s¸
a wypełnia-
logiczne
ne zerami. Natomiast dla wielkości ze znakiem spowoduje to na pewnych maszynach wypełnienie tych miejsc bitem znaku (przesuni¸
ecie arytmetyczne), a na innych zerami (przesuni¸
ecie
logiczne).
Uwaga: Nie można ich używać do danych typu float lub double.
Dopełnienie jedynkowe
&
bitowa koniunkcja
~
|
bitowa alternatywa
Zamienia każdy bit 1 na 0 i odwrotnie. Typowe użycie:
^
bitowa różnica symetryczna
y = x&~077;
«
przesuni¸
ecie w lewo
»
przesuni¸
ecie w prawo
zasłania si¸
e zerami ostatnie sześć bitów zmiennej x.
Uwaga: Ta konstrukcjanie zależyod maszyny, pod-
~
uzupełnienie jedynkowe
czas gdy:
Koniunkcja bitowa &
y = x&0177700;
zakłada 16-bitowe słowo maszynowe.
& stosuje si¸
e cz¸
esto do ”zasłaniania” pewnego zbioru bitów, np.
Przykład:
c = n&0177;
s¸
a zerowane wszystkie oprócz siedmiu najniższych bitów wartości zmiennej n.
/*
getbits: daj n bitow x od pozycji p Różnice mi¸
edzy & i &&
Zerowa pozycja bitu jest prawy koniec x; n, p sa sensownymi wielkosciami calkowitymi
*/
unsigned getbits(unsigned x, int p, int n) Np.
Jesli
x=1,
y=2
to
{
return (x >> (p+1-n)) & ~(~0 << n); x & y
ma wartosc
0
}
x && y
1
Operacje
bitowe
na
Bitowy operator alter- znakach
natywy |
Kody ASCII
Bit
7
6
5
4
3
2
1
0
Używany do ”ustawiania” bitów. Np.
0 - cyfry
0 - duże
0 - a-o
litery
x = x|M ASK;
1 - litery
1 - cyfry
cyfry
ustawia 1 na tych bitach w zmiennej x, które w M ASK s¸
a równe
/małe
/p-z
1.
litery
Bitowa różnica syme-
tryczna ^
char toupper(char c)
/*
Funkcja zamienia male litery na duze
*/
{
Ustawia jedynk¸
e na każdej pozycji bitowej tam, gdzie bity w char maska=223;
/*
223
-
11011111
*/
obu argumentach s¸
a różne, a zero tam, gdzie s¸
a takie same. Np.
return c & maska;
}
x = 011^022;
daje w rezultacie wartość 0.
char tolower(char c)
Operatory przesuni¸
ecia /* Funkcja zamienia duze litery na male */
« oraz »
{
return c | 32;
/*
32
-
00100000
*/
}
Służ¸
a do przesuwania argumentu stoj¸
acego po lewej stronie
operatora o liczb¸
e pozycji określon¸
a przez argument stoj¸
acy po
prawej stronie. Np.
y = x << 2;
char swapcase{char c)
/*
Zamiana duzych liter na male i odwrotnie
*/
przesuwa x w lewo o dwie pozycje, zwolnione bity wypełnia si¸
e
{
zerami (operacja równoważna mnożeniu przez 4.
return c ^ 32;
}
y = x >> 2;
int razy10(int n)
Priorytety i kolejność
/*
Mnozenie liczby calkowitej przez 10
przy pomocy operatorow przesuniecia
*/
obliczeń
{
int m,p;
Priorytety i ł¸
aczność operatorów
m=n<<1;
p=m<<2;
Operatory
Ł¸
acz-
return m+p;
ność
}
() [] -> .
L→R
! - ++ -- + - * & (type) sizeof R→L
Operatory i wyrażenia
* / %
L→R
przypisania
op=
+
-
L→R
i=i+3;
jest równoważne
i+=3;
<<
>>
L→R
< <= > >=
L→R
op
jest jednym z operator\’ ow:
==
!=
L→R
+
-
*
/
%
<<
>>
&
^
|
&
L→R
UWAGA:
Jezeli
wyr1
i
wyr2
sa wyrazeniami, to
^
L→R
wyr1 op= wyr2;
jest rownowazne z
|
L→R
wyr1=(wyr1) op (wyr2);
&&
L→R
Zatem przypisanie
||
L→R
x *= y+1;
jest odpowiednikiem
x=x*(y+1);
?:
L→R
Przykład:
= += -= *= /= %= ^= |= <<= >>=
R→L
,
L→R
/*
Zlicz bity argumentu o wartosci
1
*/
int bitcount(unsigned x)
Jednoargumentowe operatory +, -, * oraz & maj¸
a wyższy
{
priorytet, niż ich odpowiedniki dwuargumentowe.
int b;
Lewostrona ł¸
aczność operatora oznacza, że jeśli na tym sa-for (b=0; x!=0; x >> 1)
mym poziomie wyst¸
epuje kilka operatorów, to najpierw jest wy-if (x & 01)
konywany operator lewy.
b++;
return b;
W j¸
ezyku C nie określa si¸
e kolejności obliczania argumentów
}
operatora. Wyj¸
atki, to:
&&, ||, ?:
oraz
,
Np. w instrukcji
x=f()+g();
f może być
Wyrażenia warunkowe wykonana przed g lub odwrotnie.
Nie jest określona kolejność obliczania wartości argumentów Instrukcja realizuj¸
aca funkcj¸
e
z=max(a,b)
funkcji. Instrukcja
if (a>b)
printf ("%d %d\n", + + n, power(2, n)); z=a;
może generowć różne wyniki w zależności od kompilatora.
Możliwe s¸
a również inne efekty ”uboczne” (generowane przez else
wywołania funkcji, zagnieżdżone instrukcje przypisania oraz operatory zwi¸
ekszania i zmniejszania), np.
z=b;
a[i]=i++;
zależy
od
kolejności
aktualizacji
wartości
zmiennych
jest rownowazna
z=(a>b) ? a:b;
bior¸
acych udział w obliczeniach.
albo
z= a>b ? a:b;
Konkluzja: Pisanie programów zależnych od kolejności wyko-nania obliczeń należy do złej praktyki programowania w każdym Priorytet operatora ?: jest bardzo niski.
j¸
ezyku.
Wyrażenie warunkowe cz¸
esto wpływa na zwi¸
ezłość programu.
Np.
Sterowanie
1)
for (i=0; i<n; i++)
printf("%6d%c", a[i],
(i%10 == 9 || i== n-1) ? ’\n’:’ ’); Instrukcje i bloki
2)
printf("Masz %d czes%s.\n",n, n==1 ? "c":"ci"); Wyrażenie staje si¸
e instrukcj¸
a po zakończeniu średnikiem, np.
/* szukanie x metoda bisekcji wsrod i++;
v[0]<=v[1]<=...<=v[n-1] */
printf{"Uwaga!\n");
int binsearch(int x, int v[], int n)
{
int low=0, high, mid;
Nawiasy klamrowe
high=n-1;
{
i
}
s¸
a używane do tworzenia
while (low <= high){
bloku. (Zmienne można zadeklarować wewn¸
atrz każdego bloku.)
Po nawiasie zamyka¸
acym blok nie może wyst¸
epować średnik.
mid=(low+high)/2;
if (x<v[mid])
high=mid-1;
Instrukcja
if-else
else if (x>v[mid])
low=mid+1;
else
/* znaleziono
*/
return mid;
}
if (wyrazenie)
return -1;
/*
Nie znaleziono
*/
instrukcja1
}
else
instrukcja2
Cz¸
eść else można pomin¸
ać.
Najcz¸
eściej pisze si¸
e
if (wyrazenie)
zamiast
if (wyrazenie != 0)
Każda cz¸
eść else jest przyporz¸
adkowana najbliższej z po-
przednich instrukcji if nie zawieraj¸
acej cz¸
eści else, np.
if (n>0)
if (a>b)
z=a;
else
z=b;
Dwuznaczność ta jest szczególnie szkodliwa w takich sytu-acjach, jak
if (n>0)
for (i=0; i<n; i++)
if (s[i] > 0) {
printf("...");
return i;
}
else
/*
Zle
*/
printf("Blad -- n jest ujemne); Wci¸
ecie wyraźnie pokazuje, o co chodzi programiście, ale kompilator przyporz¸
adkuje else wewn¸
etrznej funkcji if.
konstrukcja else-if
if (wyrazenie)
instrukcja
else if (wyrazenie)
instrukcja
else if (wyrazenie)
instrukcja
Przykład: