Eine ziemlich häufiges Problem bei der Anwendungsentwicklung ist die Umwandlung von Zeichenfolgen in eine Ganzzahl zur Weiterverarbeitung. Bei C oder C++ ist atoi() der einfachste Weg, um vom char array zum int zu kommen. Leider ermöglicht atoi() keine präzise Fehlererkennung, weil eine ungültige Eingabe ebenso wie die korrekte Eingabe “0” zum Ergebnis “0” führt:
$ cat atoi.c
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("%i - %i ", atoi("invalid"), atoi("0"));
return 0;
}
$ gcc -Wall -pedantic atoi.c -o atoi
$ ./atoi 0 - 0
Meist wird empfohlen, strtol() zu nutzen. Diese Funktion ist mächtiger und v.a. brauchbarer bei der Fehlererkennung. Aber wieviel Performance kostet strtol() im Vergleich zu atoi()? Ein Shell-Script
#!/bin/bash
function instr_by_cmd()
{
valgrind --tool=callgrind --callgrind-out-file=/dev/null "$1" 2>&1 | grep refs | sed 's/^.*\s//;s/,//'
}
function print_head()
{
echo -e "\nTeste $1()";
printf "%15s | %15s | %15s\n" Test Instruktionen Ergebnis
echo "----------------+-----------------+----------------"
}
# usage: test_source "headers" "template" "replacement"
function test_source()
{
rm /tmp/source.c 2>/dev/null
for CASE in "${TESTCASES[@]}"
do
for HEADER in $1
do
echo "#include <$HEADER>" >> /tmp/source.c
done
echo "${2/CASE/$CASE}" >> /tmp/source.c
gcc /tmp/source.c -o /tmp/source 2>/dev/null
INSTR=$(instr_by_cmd "/tmp/source")
RES=$(/tmp/source);
sed -i 's/'$3'/'$RES'/' /tmp/source.c
gcc /tmp/source.c -o /tmp/source 2>/dev/null
INSTR=$(($INSTR-$(instr_by_cmd "/tmp/source")))
printf "%15s | %15s | %15s\n" ">$CASE<" $INSTR $RES
rm /tmp/source.c
done
rm atoi 2>/dev/null
}
TESTCASES=( "4" "42" "4\n2" "424242" " 42 " "answer: 42" "2147483648" "-2147483649" "\n42\n" )
print_head atoi
test_source "stdlib.h stdio.h" "int main(){char * rem=0;char * input=\"CASE\";printf(\"%i\n\", atoi(input));return 0;}" "atoi(input)"
print_head strtol
test_source "stdlib.h stdio.h" "int main(){char * rem=0;char * input=\"CASE\";printf(\"%ld\n\", strtol(input,&rem,10));return 0;}" "strtol(input,&rem,10)"
bringt zusammen mit valgrind auf der Testplattform (Core 2 Duo E6600) folgende Ergebnisse für atoi()
| Test | Instruktionen | Ergebnis |
|---|---|---|
| >4< | 883 | 4 |
| >42< | 903 | 42 |
| >4\n2< | 894 | 4 |
| >424242< | 983 | 424242 |
| > 42 < | 920 | 42 |
| >answer: 42< | 867 | 0 |
| >2147483648< | 1063 | -2147483648 |
| >-21474836489< | 1064 | 2147483647 |
| >\n42\n | 920 | 42 |
und für strtol()
| Test | Instruktionen | Ergebnis |
|---|---|---|
| >4< | 921 | 4 |
| >42< | 941 | 42 |
| >4\n2< | 932 | 4 |
| >424242< | 1021 | 424242 |
| > 42 < | 958 | 42 |
| >answer: 42< | 912 | 0 |
| >2147483648< | 1101 | 2147483648 |
| >-21474836489< | 1102 | -2147483649 |
| >\n42\n | 958 | 42 |