Finalemaskiner
På internasjonale konkurranser får man ikke bruke sin egen datamaskin, men får en maskin tildelt. NIO har pleid å gjøre det samme i finalen, både for å øve til internasjonale konkurranser, og for å gjøre det rettferdig. Har du ønske om å bruke eget tastatur er det lov å ta med.
Enten du er med i en internasjonal konkurranse, eller bruker maskiner fra Universitet i Bergen, vil du kunne forvente å bruke en Linux-maskin med følgende programmer:
firefox
- for å koble seg til konkurransesystemetgedit
- en enkel teksteditoremacs
ogvim
- litt mindre enkle teksteditorergcc
/g++
- for å kompilere C++, minst C++11.javac
+java
- for å kompilere og kjøre Java, minst Java 11.python3
- for å kjøre Python- Terminal - for å kompilere og teste programmene dine underveis
gdb
ogvalgrind
- for å debugge C++.
Resten av denne siden beskriver:
- hvordan du kan få et lignende oppsett på din egen maskin,
- hvordan du kan bruke terminalen til å teste koden din,
- litt om verktøyene du kan bruke for å debugge C++.
Sette opp egen maskin
Dersom du skal bruke din egen maskin, vil nok mye allerde være på plass. Du har en nettleser, og antageligvis en teksteditor du liker.
Teksteditorer
Dersom teksteditoren din har dusinvis med plugins og snippets, eller er et stort og tungt IDE, kan det være lurt å installere en smidig og enkel teksteditor til konkurranseprogrammering. Husk at du ikke kan ta med ferdigskrevet kode på finalen, med mindre den er skrevet ut på papir. Det er altså ikke lov å bruke templates du har lagt inn i teksteditoren.
Vi kan anbefale Notepad++ til Windows. Til macOS er TextMate et lignende alternativ. På Linux er Gedit et trygt valg. Et alternativ som finnes til alle platformene er Kate.
Programmeringsspråk
Det er lurt å installere programmeringsspråket sitt på en slik måte at du kan bruke terminalen for å kompilere og teste. På Windows er WSL en veldig rask måte å få en svært kraftig Linux-terminal. Her kan du installere programmer med Linux-distribusjonens pakkehåndterer, som for eksempel på Ubuntu:
# Kjør denne først
sudo apt update
# C++
sudo apt install gcc gdb valgrind
# Java
sudo apt install default-jdk
# Python3 (sannsynligvis allerede installert!)
sudo apt install python3
På macOS får du en C++-kompilator ved å åpne terminalen og skrive g++
.
Hvis den ikke allerede er installert vil du bli spurt om å installere.
Dokumentasjon
Dokumentasjon til de tillatte programmeringsspråkene vil ligge på konkurranseserveren, så dere trenger ikke laste ned dokumentasjon.
Bruk av terminalen
Det er veldig kjekt å kunne navigere i terminalen, slik at du finner frem til de filene du vil kompilere, teste og debugge.
Dersom du er på Windows vil denne guiden kun gjelde dersom du bruker WSL.
Navigering
Praktiske kommandoer:
pwd
- se hvilken mappe du befinner deg i (print working directory)cd mappe
- bytte mappe til oppgitt mappebanecd ..
- gå ett hakk oppover i mappe-hierarkietls
- print ut alle filer og mapper som finnes i working directoryls mappe
- print ut alle filer og mapper som finnes imappe/
mkdir ny_mappe
- lag en mappe ved navnny_mappe
mv fila.txt filb.txt
- bytt navn påfila.txt
tilfilb.txt
mv fila.txt mappe/
- flytt filenfila.txt
inn i mappenmappe/
rm fil.txt
- slett (permanent) filen ved navnfil.txt
Merk at filbaner som begynner med /
, for eksempel /bin/bash
er relative til rot-mappen.
Filbaner som ikke begynner med /
, for eksempel mappe/fil.txt
, er realative til mappen du befinner deg i.
Mappen .
er til enhver tid mappen du befinner deg i, så du kan også bruke ./mappe/fil.txt
.
For å avbryte ut av et program du har startet, trykk Ctrl-C.
Kompilering og kjøring av kode
C++
For å kompilere, og deretter kjøre, bruk:
# Kompilerer
g++ -std=c++11 -Wall -g traktor.cpp -o traktor
# Kjører
./traktor
Den øverste kommandoen tar inn en fil ved navn traktor.cpp
, og spytter ut et kjørbart program traktor
.
Det er ikke nødvendig, men ofte praktisk at filene heter det samme som oppgavene man jobber med.
Flagget -std=c++11
gjør at du får C++11-funksjonalitet,
flagget -Wall
skrur på “alle” advarsler,
og flagget -g
gjør at programfilen inneholder ekstra informasjon for debugging.
Java
I Java er det viktig at filnavnet passer til oppgaven, f.eks. traktor.java
,
og at den filen inneholder en klasse ved navn traktor
, med main-metoden inni.
# Kompilerer
javac traktor.java
# Kjører
java traktor
Den første kommandoen lager en fil traktor.class
, som den andre kommandoen kjører.
Merk at den andre kommandoen ikke skal ha med .class
-endelsen.
Python
Python trenger ikke kompileres, så bare skriv
python3 traktor.py
Mating av testinput
Når et program kjører må du skrive inn testinput, enten med tastaturet eller ved å kopiere og lime inn.
For å slippe å bruke mye tid på dette, kan du lagre en av testinputene som en fil, f.eks. sample1.txt
.
Deretter kan du kjøre programmet med den filen som input:
# C++
./traktor < sample1.txt
# Java
java traktor < sample1.txt
# Python
python3 traktor.py < sample1.txt
For å slippe å skrive dette hver gang, kan du bruke pil opp for å bla i tidligere kommandoer.
Debugging av C++
Når du skriver C++ er det fort gjort at det sniker seg inn kodefeil der du overskriver eller
leser fra steder i minnet som egentlig ikke tilhører den listen du tror det tilhører.
Når slike ting skjer, er det to mulige utfall: Enten så krasjer programmet med én gang med en
Segmentation fault
, eller så skjer det tilsynelatende ingenting.
En annen måte å krasje programmet sitt på er å forsøke å dele på 0.
Kompilatoradvarsler
Før vi tar i bruk noen tilleggsverktøy, er det lurt å få så mye bemerkninger fra kompilatoren som mulig.
Som tidligere nevnt finnes -Wall
, for å skru på advarsler. Det finnes også -Wextra
, som skrur på enda flere.
Da vil kompilatoren advare deg dersom du bruker variabler på rare måter.
GDB
Det første verktøyet vi har er gdb
, en kraftig debugger.
Vi går bare såvidt inn på alt det du kan gjøre med gdb
, så gjerne les videre andre steder.
Det viktigste når du bruker gdb
, er at programmet ble kompilert med -g
-flagget.
Da vil informasjon om koden bli lagret sammen med programmet, slik at gdb
kan
referere til linjenummer og variabelnavn i kildefilen.
For å debugge programmet ditt, bruk
gdb ./traktor
Dette vil åpne gdb
, men ikke starte programmet.
For å gjøre det skriv
run
eventuelt gi en input-fil ved å skrive
run < sample1.txt
Dette vil starte programmet, og det vil kjøre helt til det krasjer.
Når det krasjer vil gdb
ta over, og du kan skrive
bt
for å printe ut rekken med funksjonskall som til slutt endte opp på den linjen som krasjet.
Du kan også bruke
p <variabel>
for å printe ut verdiene til ulike variabler. Både globale og lokale variabler kan printes.
Man kan også printe mer avanserte uttrykk. Hvis man for eksempel har en liste med noder kalt nodes
,
og hver node har en child_count
:
p nodes[5].child_count
Valgrind
Som nevnt over er det ikke sikkert programmet ditt krasjer i det øyeblikket det gjør en ulovlig minneaksess. Programmet kan i stedet rulle videre, som gjør det vanskelig å oppdage hvor feilen ligger.
Har du lest inn fra feil adresse har du kanskje lest en verdi som er ulik hver gang du kjører programmet, som kan gi skikkelig hodebry. Hvis du har skrevet til en adresse du egentlig ikke er ment å røre, kan det hende at programmet krasjer på et senere tidspunkt, når det prøver å bruke det som lå der. Da vil krasjen inntreffe på et annet sted i koden enn der selve buggen ligger.
For å oppdage slike feil finnes valgrind
. Det er en emulator som kjører programmet ditt
og sjekker hver eneste minneaksess. Det går altså mye tregere, men vil ofte stoppe om programmet prøver å gjør noe rart.
For å bruke det, skriv valgrind
foran kommandoen du vanligvis bruker for å kjøre programmet.
Også her er det veldig lurt å ha kompilert med -g
-flagget.
Address Sanitizer & Undefined Behaviour Sanitizer
Valgrind er veldig tregt, men oppdager svært mye. Et lignende verktøy som ikke oppdager like mye, men som til gjengjeld kjører veldig mye raskere, kalless Address Sanitizer. Dersom programmet ditt prøver å gjøre noe dumt med minnet, slik som å bruke en peker til noe som ikke finnes lenger, vil programmet krasje, og fortelle deg om feilen der og da.
En nær slektning er Undefined Behaviour Sanitizer, som stopper programmet dersom det gjør noe udefinert,
slik som å la en int
bli så stor at verdien ikke lenger får plass i en int
.
Det beste med disse to verktøyene er at du ikke trenger noen ekstra programmer for å aktivere dem. De kjører også så fort at du ofte kan inkludere kommandoene fra begynnelsen av, og glemme at de er aktivert, før de plutelig rapporterer en feil du hadde oversett.
Inkluder følgende når du kompilerer koden:
g++ -Wall -g -fsanitize=address,undefined traktor.cpp -o traktor