Programmeren in C/Datatypes: verschil tussen versies

Verwijderde inhoud Toegevoegde inhoud
Sephiroth (overleg | bijdragen)
kGeen bewerkingssamenvatting
Sephiroth (overleg | bijdragen)
kGeen bewerkingssamenvatting
Regel 325:
 
''C''-pointers zijn bijzonder krachtig en daarmee ook bijzonder gevaarlijk, vooral in combinatie met ad-hoc typecasts. De reden hiervoor is dat met behulp van pointers ieder gebied in het geheugen kan worden geadresseerd buiten de controle van de compiler om. Slechts de hardware in combinatie met het Operating System verbieden toegang tot bepaalde (reeksen) adressen, de ''C'' compiler let daar volstrekt niet op, maar laat het aan de programmeur over om te zorgen dat de adressen geldig en toegankelijk zijn.
 
==Operatoren==
===Overzicht===
{{TeDoen|wat=Een tabel zou handig zijn}}
 
===Bitgerichte operatoren===
Een bitgerichte (Engels: ''bitwise'') operator is een operator (zoals plus en min er ook zijn) die toepassing kent op 'bit' niveau van de operatoren. Al de bitgerichte operatoren leunen dicht aan bij operaties die een chip meestal in hardware doet en dit is ook de context waarin deze operatoren het meest gebruikt worden. Volgende operatoren bestaan:
 
{| {{prettytable}}
|+
!Operator !! Beschrijving
|-
| && || logische AND
|-
| || || logische OR
|-
| != || logische NOT
|-
| ^ || logische XOR
|-
| << || logische shift naar links
|-
| >> || logische shift naar rechts
|-
|}
 
Merk op dat alle operatoren eveneens bestaan in hun assignatie variant (&=, |=, !=, ^=, <<= en >>=) hun werking is volkomen analoog met voorgaande operatoren zoals bijvoorbeeld + en +=. Vervolgens zullen alle bitgerichte operatoren besproken en toegelicht worden.
 
====AND====
 
De logische AND plaatst een bit op 1 indien alle bits in beide operanden (in gelijke posities) eveneens 1 zijn en 0 in andere gevallen. Zo zal
{{code
|Taal= C
|Titel=
|Code=
<source lang=c>
#include <stdio.h>
int main(int argc, char **argv){
unsigned short a = 0xff00;
unsigned short b = 0xf0f0;
unsigned short c = a & b;
printf("0x%x\n",c);
return 0;
}
</source>}}
Gelijk zijn aan ''0xf000''. In het vorige voorbeeld werd ''0xff00'' gebruikt om het hexadecimaal getal (''0x'' geeft aan dat hetgeen dat volgt hexadecimaal genoteerd zal zijn) welke 16 bit groot is op te slaan in een unsigned short. Unsigned omdat puur op bits gewerkt wordt een een tekenbit dus niet relevant is en een short omdat dit op een standaard Linux machine exact 16 bit groot is. In binair zouden de getallen a en b er respectievelijk als ''1111111100000000'' en
''1111000011110000'' uitzien. De logische functie toepassen geeft enkel een 1 op de posities waar zowel a en b tegelijk een 1 bevatten. Vervolgens wordt ''printf()'' gebruikt om het geheel hexadecimaal (''%x'') op het scherm te plaatsen.
 
Meestgebruikte toepassing van ''AND'' is om te kijken of een bepaalde vlag gezet is:
{{code
|Taal= C
|Titel=
|Code=
<source lang=c>
#define DATA_ONTVANGEN 0x2
...
unsigned char status;
...
if(status & DATA_ONTVANGEN == DATA_ONTVANGEN){
...
}
</source>}}
In dit voorbeeld wordt een statusregister van 8 bit ingevuld waarvan de op één na minst significante bit als betekenis heeft dat ''nieuwe data'' ontvangen is. Wanneer dit statusregister een ''AND'' ondergaat met het bitmasker dat enkel
deze bit bevat dient het resultaat exact gelijk te zijn aan dit bitmasker indien er data ontvangen is, anders is deze bit niet gezet.
Een tweede veelgebruikte toepassing is om een aantal bits laag te zitten. Wanneer men een waarde ''AND'' met 0x000f worden de vier minst significante bits overgenomen van de oorspronkelijke operator en worden de 12 meest significante bits zowieso op nul geplaatst.
 
====OR====
 
De logische OR plaatst een bit op 1 indien minstens één bit in beide operanden (op dezelfde positie) eveneens 1 is en 0 in andere gevallen (dus enkel nul indien ze beide nul zijn . Zo zal
{{code
|Taal= C
|Titel=
|Code=
<source lang=c>
#include <stdio.h>
int main(int argc, char **argv){
unsigned short a = 0xff00;
unsigned short b = 0xf0f0;
unsigned short c = a | b;
printf("0x%x\n",c);
return 0;
}
</source>}}
Een resultaat geven van ''0xfff0''.
 
Een ''OR'' wordt het meest gebruikt om ervoor te zorgen dat bepaalde bits aanstaan, bijvoorbeeld:
{{code
|Taal= C
|Titel=
|Code=
<source lang=c>
#define VLAG_CONTROLEER_TEMP 0x1
#define VLAG_CONTROLEER_TIJD 0x2
#define VLAG_CONTROLEER_VOLT 0x4
 
...
unsigned char commando=0;
...
commando = VLAG_CONTROLEER_TEMP | VLAG_CONTROLEER_TIJD;
...
commando |= VLAG_CONTROLEER_VOLT;
...
</source>}}
Hierbij wordt een byte als commando ergens heen gestuurd, de minst significante bit wil zeggen dat de temperatuur gecontroleerd dient et worden de op één na laagste bit wil zeggen dat de tijd gecontroleerd dient te worden en zo verder. Hier wordt het commando geïnitialiseerd zodat eerst tijd en temperatuur gecontroleerd dienen te worden (het commando bevat nu ''0x03'') vervolgens wordt ook nog de vlag gezet zodat ook het voltage gecontroleerd moet worden (commando bevat nu ''0x07''). Merk op dat de ''|='' operator dus cummulatief werkt.
 
 
====NOT====
 
Waar AND, OR en XOR binaire operatoren zijn (ze verwachten twee operanden) is NOT een unaire operator, deze verwacht maar één operand. De ''NOT'' zal de betekenis van alle bits omwisselen. Met andere woorden 0 wordt 1 en 1 wordt 0.
{{code
|Taal= C
|Titel=
|Code=
<source lang=c>
#include <stdio.h>
int main(int argc, char **argv){
unsigned short a = 0xff00;
unsigned short c = !a;
printf("0x%x\n",c);
return 0;
}
</source>}}
Zal 0x00ff als result geven. Toepassingen van de ''NOT'' zijn uiteenlopend, meestal gaat het om afgeleide toepassingen van andere poorten. Indien men, het voorbeeld van de AND indachtig, wil kijken of alle bits hoog zijn behalve een masker gebruikt men hiervoor de ''NOT''. Bij het voorbeeld van de OR kan men zo beslissen om een bepaalde bit NIET te zetten:
{{code
|Taal= C
|Titel=
|Code=
<source lang=c>
#define VLAG_CONTROLEER_TIJD 0x2
#define VLAG_CONTROLEER_VOLT 0x4
 
...
unsigned char commando=0;
...
commando = VLAG_CONTROLEER_TEMP & !VLAG_CONTROLEER_TIJD;
...
commando |= VLAG_CONTROLEER_VOLT;
...
</source>}}
Hierbij gaat werd de OR vervangen door een AND met een negatie van het bitmasker van dit bits die niet gezet dienen te worden.
 
====XOR====
 
''XOR'' (or eXclusieve OR) lijkt op de OR maar is niet zo ''makkelijk'', deze zal een bit enkel hoogplaatsen indien exact één van de bits in de operanden (op overeenstemmende positie) hoog is. In het gekende voorbeeld zal:
{{code
|Taal= C
|Titel=
|Code=<source lang=c>
#include <stdio.h>
int main(int argc, char **argv){
unsigned short a = 0xff00;
unsigned short b = 0xf0f0;
unsigned short c = a ^ b;
printf("0x%x\n",c);
return 0;
}
</source>}}
Een resultaat geven van ''0x0ff0''.
 
XOR poorten worden meestal gebruikt in meer gespecialiseerde toepassingen. Bijvoorbijld bij het berekenen van CRC checksums. Een simpele checksum bestaat bijvoorbeeld uit:
{{code
|Taal= C
|Titel=
|Code=<source lang=c>
#define SIZE 20
...
unsigned char myData[SIZE];
...
unsigned char checksum=0;
...
for(int i=0;i<SIZE;i++){
checksum ^= myData[i];
}
</source>}}
Zal een eenvoudige checksum bepalen door een logische XOR te bepalen van alle bytes in een bepaalde buffer. Veel cryptografie gerelateerde functies maken eveneens uitgebreid gebruik van de ''XOR'' functie.
 
====Shift====
 
Een shift zal een bitmasker een aantal bits opschuiven naar links ( << ) of naar rechts ( >> ). Indien naar links geshift wordt worden links nullen ingevoegd en ''valt'' het rechterdeel eraf. Een addertje is dat bij het shiften naar rechts niet 0 maar het '''tekenbit''' ingevoegd wordt. Het is dus het veiligste te werken op ''unsigned'' getallen hier. Shiften over 1 bit naar links is gelijk aan vermenigvuldigen met 2 en is shiften naar rechts (in het unsigned geval) gelijk aan delen door 2.
Een voorbeeld:
{{code
|Taal= C
|Titel=
|Code=<source lang=c>
#include <stdio.h>
int main(int argc, char **argv){
unsigned short a = 0xff00;
signed short b = 0xf0f0;
unsigned short c = a ^ b;
printf("0x%x\n",c);
c = b>>1
printf("0x%x\n",c);
return 0;
}
</source>}}
De eerste uitvoer hiervoor is 0xfe00. Binair zit het resultaat er alsvolgt uit:
 
a: 1111111100000000
a<<1:1111111000000000
 
De tweede uitvoer is 0xf878 welke eveneens logisch is, rekening houdende met het feit dat b unsigned is en het tekenbit (het eerste bit) op één stond en er dus een één (en geen nul) ingeshift werd.
 
b: 1111000011110000
b>>1:1111100001111000
 
Een shift wordt vaak gebruikt om bits te verplaatsen. Indien men wenst te weten of de 5de (minst significante) bit hoog staat shift men 1 over 5 posities en gebruikt men het voorbeeld uit ''AND'' om dit te verifiëren. Gegeven de volgende buffer:
<pre>
+---------------------------------+
|versie: 4 bit | teller 4 msb bit |
|teller 4 lsb | reserved 0xf |
+---------------------------------+
</pre>
Dus gegeven een buffer van 2 byte (char buf[2]) waarbij men de eerste vier bit een versienummer van ''4'' dient te geven, vervolgens dient men een teller te splitsen over de volgende 8 bit om te eindigen met een gereserveerd suffix dat
''0xf'' dient te zijn. Uitgewerkt geeft dit:
{{code
|Taal= C
|Titel=
|Code=<source lang=c>
#define VERSION 0x4
#define RESERVED 0xf
...
unsigned char buf[2];
...
unsigned char counter=0;
...
buf[0] = (VERSION << 4) | ((counter & 0xf0) >> 4);
buf[1] = ((counter & 0x0f) << 4) | RESERVED;
</source>}}
Dit voorbeeld combineert zowel shift, AND en OR. Bij counter worden de bits die niets nodig zijn gemaskeerd en wordt hetgeen resteert geshift zodat het op de juiste positie staat vervolgens ondergaat dit resultaat een OR met een constante.
 
[[Categorie:Programmeren in C|Datatypes]]
Informatie afkomstig van https://nl.wikibooks.org Wikibooks NL.
Wikibooks NL is onderdeel van de wikimediafoundation.