5

The following line of code produces a compiler warning with HP-UX's C++ compiler:

strcpy(var, "string")

Output:

error #2167: argument of type "unsigned char *" 
    is incompatible with parameter of type "char *"

Please note: var is the unsigned char * here - its data type is outside of my control.

Two questions:

  1. What does incompatibility mean in the context of these two types? What would happen if the compiler was forced to accept the conversion? An example would be appreciated.
  2. What would be a safe way to make the above line of code work, assuming I have to use strcpy?
Hassaan
  • 253
  • 4
  • 13
  • noting really to makes you worry, just strcpy( (char*)var, "string"); – nullqube Mar 08 '18 at 05:17
  • `char`, `signed char` and `unsigned char` are distinct types. You can't use an `unsigned char *` where a `char *` is expected, and vice versa, without using type casts. But why are you passing an `unsigned char *` to a `char *` based API to begin with? What kind of data does the `unsigned char *` point to? You might consider using `memcpy()` instead. – Remy Lebeau Mar 08 '18 at 05:18
  • It would be helpful to include an [MCVE](https://stackoverflow.com/help/mcve) in this question showing the definition of `var`. It would also be helpful to include the version of HP-UX and/or the compiler you're using. – MrEricSir Mar 08 '18 at 05:57
  • The second question is a duplicate of [How to convert a string literal to unsigned char array in visual c++](https://stackoverflow.com/q/2206050/5376789) – xskxzr Mar 08 '18 at 16:18

3 Answers3

4

C++ is being strict in checking the types where std::strcpy expects a char* and your variable var is an unsigned char*.

Fortunately, in this case, it is perfectly safe to cast the pointer to a char* like this:

std::strcpy(reinterpret_cast<char*>(var), "string");

That is because, according to the standard, char, unsigned char and signed char can each alias one another.

Galik
  • 47,303
  • 4
  • 80
  • 117
  • But if they can alias each other then what is the rationale in making the compiler throw an error? Is there some edge case that would make the cast unsafe? – Hassaan Mar 08 '18 at 06:12
  • 1
    @M.Hassaan I think it's just general type safety helping you avoid accidentally using the wrong variable. By making the user provide an explicit cast it helps to ensure you know what they are doing. The cast is always safe respecting strict aliasing rules. – Galik Mar 08 '18 at 06:25
  • It should be `reinterpret_cast` – M.M Mar 08 '18 at 08:04
1

In C Standard, the char is Impementation Defined. ANSI C provides three kinds of character types(All three take one byte): char, signed char, unsigned char. Not just like short, int, only two.

You can try:

char *str="abcd"; signed char *s_str = str;

The compiler will warn the second line of the code is error.It just like:

short num = 10; unsigned short *p_num = &num;

The compiler will warn too. Because they are different type defined in compiler.

So, if you write 'strcpy( (char*)var, "string")',the code just copy the characters from "string"'s space to 'var's space. Whether there is a bug here depends on what do you do with 'var'. Because 'var' is not a 'char *'

Gleipnir
  • 36
  • 4
1

char, signed char, and unsigned char are distinct types in C++. And pointers to them are incompatible - for example forcing a compiler to convert a unsigned char * to char * in order to pass it to strcpy() formally results in undefined behaviour - when the pointer is subsequently dereferenced - in several cases. Hence the warning.

Rather than using strcpy() (and therefore having to force conversions of pointers) you would be better off doing (C++11 and later)

const char thing[] = "string";
std::copy(std::begin(thing), std::end(thing), var);

which does not have undefined behaviour.

Even better, consider using standard containers, such as a std::vector<unsigned char> and a std::string, rather than working with raw arrays. All standard containers provide a means of accessing their data (e.g. for passing a suitable pointer to a function in a legacy API).

Peter
  • 35,646
  • 4
  • 32
  • 74
  • By "forcing the compiler" do you mean casting? And could you kindly give an example in your answer of a scenario in which using `strcpy()` in this way would cause unwanted behavior? – Hassaan Mar 08 '18 at 10:12