cast unsigned char * (uint8_t *) to const char *
Solution 1
It is safe. The error has to do with mixing unsigned integers of 8 bits with characters, that are signed if you use just char
.
I see, however, that the function accepts uint8_t
and does char
acter arithmetic, so it should accepts char
s (or const char
s, for the matter). Note that a character constant 'c'
is of type char
, and you're mixing signed and unsigned in the expressions inside ihex_decode
, so you have to be careful to avoid overflows or negative numbers treated as big positive numbers.
A last style note. As in
is not modified, it should read const uint8_t* in
(or const char* in
, as of above) in the parameters. Another style error (that may lead to very bad errors) is that you accept len
as size_t
, but declare the i
loop variable as uint8_t
. What if the string is more than 255 bytes in length?
Solution 2
This is safe. The warning (I think) pops up because you're casting from unsigned to signed.
Solution 3
Everything which is non-const * can be safely casted to const * in C. It's save.
Loïc G.
I'm a hobbyist programmer. I mostly use Python but also PHP, Javascript (JQuery). As well, I'm a hobbyist electronician and I use C with avr-gcc to program microcontrollers such as Atmel AVR.
Updated on August 11, 2020Comments
-
Loïc G. over 3 years
I've a function which take an uint8_t * argument :
uint8_t* ihex_decode(uint8_t *in, size_t len, uint8_t *out) { uint8_t i, hn, ln; for (i = 0; i < len; i+=2) { hn = in[i] > '9' ? (in[i]|32) - 'a' + 10 : in[i] - '0'; ln = in[i+1] > '9' ? (in[i+1]|32) - 'a' + 10 : in[i+1] - '0'; out[i/2] = (hn << 4 ) | ln; } return out; }
I use this function with :
uint8_t data[SPM_PAGESIZE]; // SPM_PAGESIZE = 256 bytes uint8_t sysex_data[SPM_PAGESIZE/2]; ihex_decode(data, strlen(data), sysex_data);
But in this case, my compiler (avr-gcc) return a warning :
main.c|89|warning: pointer targets in passing argument 1 of 'strlen' differ in signedness /usr/include/string.h|399|note: expected 'const char *' but argument is of type 'uint8_t *'
So, i've found a solution by type casting the data var :
ihex_decode(data, strlen((const char *)data), sysex_data);
The warning disappears but I wonder if this solution is safe.
Is there a better way ?
Thanks
-
cnicutar over 12 yearsBut the warning isn't about discarding
const
qualifiers. -
TOMKA over 12 yearsThe warning is regarding the conversion from
uint8_t *
tochar *
-
TOMKA over 12 yearsI'm not entirely sure it is safe. What would be the purpose of the warning if there were no consequences?
-
Loïc G. over 12 yearsNot because strlen() expects a const char * ?
-
Patrick B. over 12 yearsThe question I answered was: 'I wonder if this solution is safe.'. I answered it.
-
Mihails Strasuns over 12 yearsNo, char* can always be cast to const char* implicitly, as it only strengthens the restrictions. signed <-> unsigned, however, may change the interpretation of data and break some algorithms, so there is a warning about it. 0 is the same though in both representations, so strlen should work just fine.
-
Rudy Velthuis over 12 yearsChar can be signed or unsigned, that is up to the implementation, AFAIK.
-
Diego Sevilla over 12 yearsOK, @Rudy, add up "in this case" :)
-
Loïc G. over 12 yearsYou say i'm mixing signed and unsigned inside
ihex_decode()
. When the type is signed ? In fact, if I change, inihex_decode()
:'9'
to57
,'a'
to97
and'0'
to48
(changing ASCII symbols to their decimal value), is the function can acceptuint8_t *
? -
Lundin over 12 years'c' is an int. In reality there is no such thing as character literals, the
' '
is just cosmetic goo to hide away the raw ASCII table for the programmer. Try to printsizeof('c')
if you don't believe me. -
JeremyP over 12 yearsActually, it's not safe theoretically, although no real world implementation I've ever seen would have a problem. It's possible for char to have more than 8 bits. In such an implementation, uint8_t would be have to the same size as char (since
sizeof(char)
is 1) but would ignore the top few bits. So an implementation might see a uint8_t as zero but non zero if cast to a char. Thus strlen could index off the end of the array. -
TOMKA over 12 years@JeremyP:
uint8_t
is an exact width type, if an implementation does not have a type that is exactly 8 bits, then it does not have to provideuint8_t
. -
12431234123412341234123 over 3 years@JeremyP
uint8_t
does not have padding. If there is no type with exactly 8 bit without padding,uint8_t
will not exist. C11 - 7.20.1.1 Exact-width integer types - 2: The typedef nameuintN_t
designates an unsigned integer type with width N and no padding bits. .... and 3: These types are optional. ...