Hyödyllisiä käännöslippuja
-Wall
Asettaa monia hyödyllisiä varoituksia päälle. Bugi saattaa löytyä miettimällä tarkkaan, mitä varoitus tarkoittaa. Tätä kannattaa käyttää aina.
-fsanitize=address
Tarkistaa kaikki muistinkäytöt, ja lopettaa koodin suorituksen heti, kun muistia käytetään virheellisesti. Tämä on hyödyllinen, koska monet muistivirheet, kuten pienet taulukonylitykset, eivät aiheuta segfaultia suoraan, vaan virhe ilmenee usein vasta myöhemmin arvaamattomalla tavalla.
-D_GLIBCXX_DEBUG
Standardikirjaston käsinkirjoitettu debug-toiminnallisuus. Kuten -fsanitize=address
, havaitsee muistivirheitä ja iteraattorien väärinkäyttöä. Se voi myös huomata hienovaraisempia bugeja, kuin pelkkiä muistivirheitä, ja antaa hyödyllisemmän kuvauksen virheestä.
Assert
assert(ehto);
assert
-funktio kaataa ohjelman heti, jos annettu ehto ei päde. Hyvin hyödyllinen bugin juurisyyn etsimisessä, eli "missä kohtaa menee pieleen".
Brutetestaus
Brutetesterin voi kirjoittaa monella tavalla, mutta ainakin jokin tapa on hyvä osata rutiinilla.
Alla esimerkki C++-brutetestaajan rungosta. Varsinainen koodi on tiedostossa koodi.cpp
käännettynä tiedostoon koodi
, bruteratkaisu on tiedostossa brute.cpp
, käännettynä brute
.
#include <bits/stdc++.h> using namespace std; int main() { while (true) { // Generoi sattumanvarainen syöte tiedostoon ofstream f("syote"); int n = rand()%10+1; f << n << endl; f.close(); // Aja molemmat koodit system("./brute < syote > out_brute"); system("./koodi < syote > out_koodi"); // Vertaa tulosteita if (system("diff -b out_brute out_koodi")) { cout << "Virhe löytyi!" << endl; break; } } }
Komento diff
lipulla -b
vertailee kätevästi tulosteita välittämättä ylimääräisistä välilyönneistä, kuten kisajärjestelmätkin.
HUOM: Aiemmin tässä mainittu -w
-lippu ei toimi ihan halutusti, vaan se ei välitä välilyönneistä ollenkaan. -b
harmillisesti erottaa rivinvaihdot ja välilyönnit.
Välillä ei ole tarkoituskaan, että tulosteet ovat identtisiä, vaan oikeellisuus pitää tarkastaa jollain toisella tavalla. Tällöin tulosteet voidaan lukea käyttäen ifstream
-virtoja:
// Vertaa tulosteiden ensimmäistä lukua ifstream fa("out_brute"), fb("out_koodi"); long a, b; fa >> a; fb >> b; if (a != b) { cout << "Virhe löytyi!" << endl; break; }
Jos ja kun brutetesteri löytää virheen, pysähtymisen jälkeen tiedostot syote
, out_brute
, out_koodi
vastaavat sitä syötettä, jolla virhe löytyi. Koodia voi siis ajaa samalla syötteellä uudestaan. Voi olla hyödyllistä ottaa syöte talteen, ettei vahingossa ylikirjoita sitä myöhemmin.
cp syote syote_rikki ./koodi < syote_rikki
Syötettä voi myös käyttää GDB:ssä (muista oikeat käännösliput, ks. GDB-ohje):
gdb koodi run < syote_rikki
Toinen hyvä kieli brutetesterin toteuttamisielle on Python, tai miksei Bash-skriptikin, jos syötteen generointi tapahtuu toisessa ohjelmassa.