Programmeren in C/Datatypes: verschil tussen versies

Verwijderde inhoud Toegevoegde inhoud
Madyno (overleg | bijdragen)
Geen bewerkingssamenvatting
DimiC88 (overleg | bijdragen)
kGeen bewerkingssamenvatting
 
Regel 126:
|Titel=
|Code=
<sourcesyntaxhighlight lang="c">
#include <stdio.h>
#include <stdlib.h>
Regel 145:
return EXIT_SUCCESS;
}
</syntaxhighlight>
</source>
}}
Bovenstaande code zal niet het resultaat opleveren dat de naïeve programmeur ervan verwacht, ondanks het feit dat 3*(1/3) wel degelijk 1 is. Dit ligt aan het feit dat een binaire representatie van 1/3 als floating point onmogelijk is en er dus een fout wordt geïntroduceerd. Een heel kleine fout weliswaar, afhankelijk van de precisie van ''double'' op het platform in kwestie, maar genoeg om de ''is gelijk''-operator te ondermijnen. Over het algemeen kan men stellen dat het gebruik van de ''=='' (is-gelijk) operator met twee floating-point getallen uit den boze is.
Regel 154:
|Titel=
|Code=
<sourcesyntaxhighlight lang="c">
#include <math.h>
#include <stdio.h>
Regel 177:
return EXIT_SUCCESS;
}
</syntaxhighlight>
</source>
}}
En "''Hey, Presto!''". De code werkt zoals het de bedoeling is omdat we nu rekening houden met de inherente fout die het gebruik van floating-point getallen oplevert. Met behulp van "''fabs(x*3 - 1.0) < EPSILON''" wordt het absolute verschil uitgerekend en als dit kleiner is dan een voorgedefinieerd maximum ('''EPSILON''') zijn de twee waarden "gelijk" of in ieder geval "nagenoeg gelijk". In de wandeling staat deze techniek ook wel bekend als "''close-enough comparison''". Een goede waarde voor EPSILON hangt af van de toepassing en de implementatie van de compiler (dus "''[[:w:RTFM|RTFM]]''", nogmaals).
Regel 187:
|Titel=
|Code=
<sourcesyntaxhighlight lang=c>unsigned int i;</sourcesyntaxhighlight>
}}
Dit declareert een integer zonder tekenbit, dit wil zeggen dat een extra bitpositie vrijkomt voor ''nuttigere'' informatie en dat tweemaal zo grote getallen opgeslagen kunnen worden.
Regel 198:
|Titel=
|Code=
<sourcesyntaxhighlight lang="c">
#include <stdio.h>
int main(){
Regel 211:
return 0;
}
</syntaxhighlight>
</source>
}}
De uitvoer op een 32 bit Linux systeem is (uit deze uitvoer volgt automatisch dat het een 32 bit-systeem is. Kijk maar naar de grootte van een pointer, deze is 4 byte, dus 32 bit):
Regel 232:
|Titel=
|Code=
<sourcesyntaxhighlight lang="c">
enum kleur
{
Regel 239:
Blauw
};
</syntaxhighlight>
</source>
}}
Deze code definieert een datatype 'kleur' als een opsomming met drie mogelijke waarden. Aan elk van deze waarden wordt een numerieke waarde toegekend, maar welke waarde dit precies is, is hier ongedefinieerd. Als het wenselijk is dat deze drie een specifieke waarde hebben, kan dat ook:
Regel 246:
|Titel=
|Code=
<sourcesyntaxhighlight lang="c">
enum kleur
{
Regel 253:
Blauw /* Blauw heeft nu een numerieke waarde '2' */
};
</syntaxhighlight>
</source>
}}
De waarde '''Rood''' is nu equivalent aan '''0''', groen aan '''1''' en blauw aan '''2'''. Let wel dat het daarmee nog steeds geen ''int'' is, maar een afzonderlijk datatype.
Regel 260:
|Titel=
|Code=
<sourcesyntaxhighlight lang="c">
enum kleur
{
Regel 274:
i = Rood; /* Ok, de enum wordt "gepromoveerd" naar een int */
k = 21231; /* FOUT, hoewel de compiler er geen error op zal genereren. */
</syntaxhighlight>
</source>
}}
Het type dat de ''enum'' representeert is sterk van de compiler afhankelijk. Dit '''kan''' een ''int'' zijn, maar het type is compiler-afhankelijk. De toekenning "''k=21231''" neemt aan dat dit type groot genoeg is om 21231 te bevatten, maar er bestaat geen garantie dat dat inderdaad zo is. Bovendien is het doel van een enum een type te definieren dat alleen bepaalde waarden kan bevatten, als we daar dan allerlei andere waarden in gaan stoppen, zetten we onze medeprogrammeurs op het verkeerde been en de fouten zijn voorgeprogrammeerd. Niet goed, niet doen, dus.
Regel 284:
|Titel=
|Code=
<sourcesyntaxhighlight lang="c">
/* Dit is een functie die geen argumenten heeft en geen waarden teruggeeft. */
void foobar(void)
Regel 290:
printf("Helemaal NIETS\n");
}
</syntaxhighlight>
</source>
}}
 
Regel 329:
|Titel=
|Code=
<sourcesyntaxhighlight lang="c">
void foobar(void)
{
Regel 350:
funp = foobar; /* funp bevat nu een pointer naar *deze* functie! (foobar) */
}
</syntaxhighlight>
</source>
}}
Om aan te geven dat een pointer '''nergens''' naar wijst, kan een '''0''' (of, wat netter, ''NULL'') aan die pointer worden toegekend. Het resultaat ervan is dat de pointer een ''null-pointer'' wordt, een bijzondere waarde die, als de pointer wordt gevolgd (''gedereferenced'' in vakjargon) veelal in een exceptie resulteert. Officieel is dit echter niet meer dan ''undefined behavior'', ongedefinieerd gedrag. Dit verschijnsel is een veelvoorkomende oorzaak van programma-''crashes''. De representatie van een ''null-pointer'' is overigens volledig compiler afhankelijk, de enige voorwaarde die de standaard stelt is dat het geen geldige waarde voor een pointer mag zijn.
Regel 393:
|Titel=
|Code=
<sourcesyntaxhighlight lang=c>
#include <stdio.h>
int main(int argc, char **argv){
Regel 402:
return 0;
}
</sourcesyntaxhighlight>}}
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.
Regel 411:
|Titel=
|Code=
<sourcesyntaxhighlight lang=c>
#define DATA_ONTVANGEN 0x2
...
Regel 419:
...
}
</sourcesyntaxhighlight>}}
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.
Regel 431:
|Titel=
|Code=
<sourcesyntaxhighlight lang=c>
#include <stdio.h>
int main(int argc, char **argv){
Regel 440:
return 0;
}
</sourcesyntaxhighlight>}}
Een resultaat geven van ''0xfff0''.
 
Regel 448:
|Titel=
|Code=
<sourcesyntaxhighlight lang=c>
#define VLAG_CONTROLEER_TEMP 0x1
#define VLAG_CONTROLEER_TIJD 0x2
Regel 460:
commando |= VLAG_CONTROLEER_VOLT;
...
</sourcesyntaxhighlight>}}
Hierbij wordt een byte als commando ergens heen gestuurd, de minst significante bit wil zeggen dat de temperatuur gecontroleerd dient te 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.
 
Regel 471:
|Titel=
|Code=
<sourcesyntaxhighlight lang=c>
#include <stdio.h>
int main(int argc, char **argv){
Regel 479:
return 0;
}
</sourcesyntaxhighlight>}}
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
Regel 485:
|Titel=
|Code=
<sourcesyntaxhighlight lang="c">
#define VLAG_CONTROLEER_TIJD 0x2
#define VLAG_CONTROLEER_VOLT 0x4
Regel 496:
commando |= VLAG_CONTROLEER_VOLT;
...
</sourcesyntaxhighlight>}}
Hierbij gaat werd de OR vervangen door een AND met een negatie van het bitmasker van dit bits die niet gezet dienen te worden.
 
Regel 505:
|Taal= C
|Titel=
|Code=<sourcesyntaxhighlight lang="c">
#include <stdio.h>
int main(int argc, char **argv){
Regel 514:
return 0;
}
</sourcesyntaxhighlight>}}
Een resultaat geven van ''0x0ff0''.
 
Regel 521:
|Taal= C
|Titel=
|Code=<sourcesyntaxhighlight lang="c">
#define SIZE 20
...
Regel 531:
checksum ^= myData[i];
}
</sourcesyntaxhighlight>}}
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.
 
Regel 541:
|Taal= C
|Titel=
|Code=<sourcesyntaxhighlight lang="c">
#include <stdio.h>
int main(int argc, char **argv){
Regel 552:
return 0;
}
</sourcesyntaxhighlight>}}
De eerste uitvoer hiervoor is 0xfe00. Binair zit het resultaat er alsvolgt uit:
 
Regel 575:
|Taal= C
|Titel=
|Code=<sourcesyntaxhighlight lang="c">
#define VERSION 0x4
#define RESERVED 0xf
Regel 585:
buf[0] = (VERSION << 4) | ((counter & 0xf0) >> 4);
buf[1] = ((counter & 0x0f) << 4) | RESERVED;
</sourcesyntaxhighlight>}}
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.
 
Informatie afkomstig van https://nl.wikibooks.org Wikibooks NL.
Wikibooks NL is onderdeel van de wikimediafoundation.