1

I'm trying to pass a string to a function:

void PassString(unsigned char * value)
{
    // ...
}

int main(void)
{
    while(1)
    {
        PassString("TEST");
    }
}

I'm getting warning: (359) illegal conversion between pointer types.

Swordfish
  • 12,971
  • 3
  • 21
  • 43
ddd
  • 85
  • 2
  • 10
  • maybe in your env, string literals are `signed char *`? – Sourav Ghosh Nov 08 '18 at 11:56
  • Also "TEST" is a constant. – Gem Taylor Nov 08 '18 at 11:57
  • @GemTaylor True, but unrelated to the warning message in question. – Sourav Ghosh Nov 08 '18 at 12:09
  • @SouravGhosh Actually it shouldn't even matter if `char`s are signed are not. `char []` can't be automatically converted to `signed char*` nor to `unsigned char *`. – HolyBlackCat Nov 08 '18 at 12:18
  • @SouravGhosh OK so const conversion might generate a different warning, but a decent C compiler should generate a warning or error for it these days. – Gem Taylor Nov 08 '18 at 12:24
  • @SouravGhosh string literals must be `char[N]` – M.M Nov 08 '18 at 12:27
  • @M.M yes sir, and sign of `char` is implementation specific, is not it? – Sourav Ghosh Nov 08 '18 at 12:32
  • @HolyBlackCat Not automatic sir, plain `char` is signed or unsigned, is implementation specific. For an implementation, where plain `char` is `unsigned`, the above code should not produce any warning, I believe. – Sourav Ghosh Nov 08 '18 at 12:35
  • @SouravGhosh yes but it is a different type to `signed char` and `unsigned char`. Even if the same signedness as one or the other. – M.M Nov 08 '18 at 12:41
  • @M.M Completely agree. `char` is the only case I guess where `char` and `signed char` are mentioned to be different types in the standard. `int`, on other hand, is `signed int` - by default, thus, they are same types. – Sourav Ghosh Nov 08 '18 at 12:44
  • @ Gem Taylor your answer has worked! const unsigned char * has worked perfect for me. Mark it as answer. – ddd Nov 08 '18 at 12:54
  • const unsigned char * merely silences the warning, it does not solve the underlying issue. What compiler do you use? GCC gives a more specific warning: "pointer targets differ in signedness." – GermanNerd Nov 08 '18 at 13:08
  • Xc8 compiler... – ddd Nov 08 '18 at 13:48

2 Answers2

3

The string literal being passed is of type char [] but the argument is given as unsigned char *.

So change the type of the argument to char[].

lost_in_the_source
  • 10,998
  • 9
  • 46
  • 75
  • 2
    Or to `char *`. – HolyBlackCat Nov 08 '18 at 12:17
  • “the argument is given as `unsigned char *`” should be “the parameter type is `unsigned char *`”. There is some historic mixing of these terms, but the C standard defines *parameter* as an object declared as part of a function declaration that acquires a value on entry to a function and *argument* as an expression in the parentheses of a function call. In other words, an *argument* is the expression that is passed, and a *parameter* is the container for the thing that is received. – Eric Postpischil Nov 08 '18 at 14:43
  • Although the string literal is of type `char []`, it is not passed to the function. First, it is automatically converted to `char *`, so it is a `char *` that is passed to the function, not a string literal or a `char []`. – Eric Postpischil Nov 08 '18 at 14:44
2

Short answer:

String literals such as "TEST" are of type char[] in C.

So change the function to accept char*. Or cast the argument to unsigned char*, even though that's a less clean solution.


Some history behind char:

The C type system is a bit dysfunctional when it comes to the character types. In the dawn of time when dinosaurs walked the earth, it wasn't specified if char should be signed or unsigned per default.

signed made sense because that makes char consistent with the larger integer types. unsigned also made sense, because there exist no character symbol tables with negative indices.

Upon language standardization, there already existed various compilers that gave char different signedness. So it was decided that the signedness of char should be implementation-defined. That is: each compiler decides.

For the same reason, the types char, signed char and unsigned char were stated to be 3 different types. This means that you cannot implicitly convert between pointers to these types. Instead you need to use an explicit conversion by casting.

Only the character types behave this weird. If you take for example int and signed int they are always compatible and int is always signed.

This is a known shortcoming of the C language. The types from the stdint.h library are therefore preferred over "raw" character types.


Best practice using character types:

  • Use the type char if you are dealing with (up to 8 bit) text strings, and only then.
  • Use the type unsigned char or uint8_t if you are dealing with raw binary data or doing type punning etc.
  • Use signed char or int8_t if you are doing signed 8 bit integer arithmetic.
  • Use unsigned char or uint8_t if you are doing unsigned 8 bit integer arithmetic.
  • There is never any danger converting between the various character types unless signedness matters.
  • But... be careful when doing any form of arithmetic on these types, since it comes with many pitfalls. See Implicit type promotion rules.
Lundin
  • 195,001
  • 40
  • 254
  • 396