Mind, using built in library functions usually results in tighter code -- it's tightly integrated with the compiler so that minimal overhead can be emitted. Here's an example from the project I'm playing with right now;
00000fcc <__itoa_ncheck>:
fcc: bb 27 eor r27, r27
fce: 4a 30 cpi r20, 0x0A ; 10
fd0: 31 f4 brne .+12 ; 0xfde <__itoa_ncheck+0x12>
fd2: 99 23 and r25, r25
fd4: 22 f4 brpl .+8 ; 0xfde <__itoa_ncheck+0x12>
fd6: bd e2 ldi r27, 0x2D ; 45
fd8: 90 95 com r25
fda: 81 95 neg r24
fdc: 9f 4f sbci r25, 0xFF ; 255
fde: 0c 94 f2 07 jmp 0xfe4 ; 0xfe4 <__utoa_common>
00000fe2 <__utoa_ncheck>:
fe2: bb 27 eor r27, r27
00000fe4 <__utoa_common>:
fe4: fb 01 movw r30, r22
fe6: 55 27 eor r21, r21
fe8: aa 27 eor r26, r26
fea: 88 0f add r24, r24
fec: 99 1f adc r25, r25
fee: aa 1f adc r26, r26
ff0: a4 17 cp r26, r20
ff2: 10 f0 brcs .+4 ; 0xff8 <__utoa_common+0x14>
ff4: a4 1b sub r26, r20
ff6: 83 95 inc r24
ff8: 50 51 subi r21, 0x10 ; 16
ffa: b9 f7 brne .-18 ; 0xfea <__utoa_common+0x6>
ffc: a0 5d subi r26, 0xD0 ; 208
ffe: aa 33 cpi r26, 0x3A ; 58
1000: 08 f0 brcs .+2 ; 0x1004 <__utoa_common+0x20>
1002: a9 5d subi r26, 0xD9 ; 217
1004: a1 93 st Z+, r26
1006: 00 97 sbiw r24, 0x00 ; 0
1008: 79 f7 brne .-34 ; 0xfe8 <__utoa_common+0x4>
100a: b1 11 cpse r27, r1
100c: b1 93 st Z+, r27
100e: 11 92 st Z+, r1
1010: cb 01 movw r24, r22
1012: 0c 94 0b 08 jmp 0x1016 ; 0x1016 <strrev>
As you can see, it's no ordinary function, it has multiple entry points! There is no preamble, saving registers or setting a stack frame, as it doesn't use either (only clobber registers (r18-r25) are used, and the buffer is external).
Heh. That's silly, and a little annoying: strrev isn't called from anywhere else, and it immediately follows this call (0x1016 is the very next instruction). Wasted jump. One of the downsides to linking premade object (I think?), it doesn't try to optimize it.
Anyway, can be better than compiled code, but clearly, also can be worse in some respects. YMMV.
One notable downside is whether the libraries include different platform support or not. ATtiny doesn't do MUL (IIRC?). So you have to use subtraction or (shift-accumulate) division.
If you're only using chars and not ints, you could save even more (only needs to parse 3 digits, not 5?), but if you need both sizes, you're stuck with the bigger one.
If you do have MUL handy, you can implement division by 10 as multiplication by 6553, keeping a few extra bits to account for the fact that it's actually 6553.6 in fixed point (which requires 24 bits; avr-gcc supports __uint24 if you wish to do it in C). I've written this before (in asm) and it's competitive in speed and size.
Tim