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 |