Expanding my comment into something resembling an answer.
The strcat()
function expects plain char *:
char *strcpy(char * restrict s1, const char * restrict s2);
You're passing unsigned char *
. These are different types (even when plain char
is an unsigned type). The str*()
functions are not designed to take arrays of unsigned char
. To 'placate' (or 'coerce') the compiler into accepting the call, you'll need to cast the pointers:
strcat((char *)msg, (char *)buf);
Or write and use a series of functions that do this automatically:
static inline unsigned char *ustrcat(unsigned char *dst, const unsigned char *src)
{
return (unsigned char *)strcat((char *)dst, (char *)src);
}
This could be a good idea if you need to use the functions frequently; it means you don't have to leave so many unsightly casts around your code. You can add the restrict
qualifiers if you prefer.
Note that the three types char
, unsigned char
and signed char
are distinct, even though plain char
has the same range of values as one of the other two. ISO/IEC 9899:2011 §6.2.5 Types says:
¶15 The three types char
, signed char
, and unsigned char
are collectively called
the character types. The implementation shall define char
to have the same range,
representation, and behavior as either signed char
or unsigned char
.45)
45) CHAR_MIN
, defined in <limits.h>
, will have one of the values 0
or SCHAR_MIN
, and this can be
used to distinguish the two options. Irrespective of the choice made, char
is a separate type from the
other two and is not compatible with either.
Your code is vulnerable to buffer overflows because you aren't checking lengths anywhere. This is tangential to the compilation warnings you're getting, but you should make sure that you do not copy too much data into the destination buffer.
You also tried:
unsigned const char *buf[255];
unsigned char *msg[255];
strcat(msg, buf);
Now you're passing pointers to pointers to a function that only expects pointers to char
— the compiler is right to complain.