Learning embedded C while working in MPLAB X with a PIC24FJ128GB204.
So far, I've mostly heard that you should use unsigned types as much as possible (especially?) on embedded devices, so I've started to use uint8_t arrays to hold strings. However, if I call itoa from stdlib.h, it expects a pointer to a signed char (int8_t) array:
extern char * itoa(char * buf, int val, int base);
This is made specifically clear when I try to compile after using itoa on an unsigned array:
main.c:317:9: warning: pointer targets in passing argument 1 of 'itoa' differ in signedness
c:\program files (x86)\microchip\xc16\v1.36\bin\bin\../..\include/stdlib.h:131:15: note: expected 'char *' but argument is of type 'unsigned char *'
Searching for implementations of itoa on other platforms, that seems to be the common case.
Why is that?
(I've also noticed that most implementations expect value/pointer/radix whereas -for some reason- the stdlib.h from Microchip expects the pointer first. It took me a while to realize this.)
This is true mainly for the reason that (accidentally or intentionally) signed operands mixed with the bitwise operators create havoc. But also there aren't many cases in low level programming where you actually need to use signed types.
For example, MISRA-C enforces you to always use unsigned variables, operands and integer constant unless the intention is to actually use a signed type. So this isn't just something opinion-based, MISRA-C is de facto industry standard for most professional embedded systems.
That's ok but it isn't wrong to use
charfor that purpose either. The only time when it is ok to usecharis when you intend to store text. Note thatcharis especially nasty, because unlike all other types in the language, it has unknown signedness. Each compiler can makechareither signed or unsigned and still conform with the C standard. So code relying oncharbeing either signed or unsigned is broken. However, for text strings this doesn't matter since they are always positive.Your compiler apparently treats
charas signed then. First of all please note thatitoaisn't standard C and isn't allowed to exist insidestdlib.hwhen strict C standard conformance is desired. But more importantly, different compilers might implement the function differently since it isn't standardized.As it turns out, you can safely cast wildly between the various character types:
char,unsigned char,signed char,int8_tanduint8_t(the stdint.h 8 bit types are pretty much dead certain to be character types even though the standard doesn't say so explicitly). The character types specifically have various special rules associated with them, meaning that you can always cast something to a character type.You can safely cast your
uint8_tarray to achar*, as long as there are no qualifiers (constetc) present.