Converting char* to unsigned char*

46,814

Solution 1

To avoid the compiler warning, you simply need:

strncpy((char *)digest, argv[2], 20);

But avoiding the compiler warning is often not a good idea; it's telling you that there is a fundamental incompatibility. In this case, the incompatibility is that char has a range of -128 to +127 (typically), whereas unsigned char is 0 to +255.

Solution 2

You can't correctly copy it since there is difference in types, compiler warns you just about that.

If you need to copy raw bits of argv[2] array you should use memcpy function.

Solution 3

Cast the signedness away in the strncpy() call

strncpy((char*)digest, argv[2], 20);

or introduce another variable

#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
    unsigned char *digest;
    void *tmp;                   /* (void*) is compatible with both (char*) and (unsigned char*) */

    digest = malloc(20 * sizeof *digest);
    if (digest) {
        tmp = digest;
        if (argc > 2) strncpy(tmp, argv[2], 20);
        free(digest);
    } else {
        fprintf(stderr, "No memory.\n");
    }
    return 0;
}

Also note that malloc(20 * sizeof(unsigned char*)) is probably not what you want. I think you want malloc(20 * sizeof(unsigned char)), or, as by definition sizeof (unsigned char) is 1, malloc(20). If you really want to use the size of each element in the call, use the object itself, like in my code above.

Solution 4

You can use memcpy as:

memcpy(digest, argv[2], strlen(argv[2]) + 1);

as the underlying type of objects pointed to by src and dest pointers are irrelevant for this function.

Solution 5

Just put (char*) in front of it or (unsigned char*)

Share:
46,814
Rajiv
Author by

Rajiv

Updated on June 09, 2020

Comments

  • Rajiv
    Rajiv almost 4 years

    How do I copy a char* to a unsigned char* correctly in C. Following is my code

    int main(int argc, char **argv)
    {
        unsigned char *digest;
    
        digest = malloc(20 * sizeof(unsigned char));
        strncpy(digest, argv[2], 20);
        return 0;
    }
    

    I would like to correctly copy char* array to unsigned char* array. I get the following warning using the above code

    warning: pointer targets in passing argument 1 of âstrncpyâ differ in signedness 
    

    EDIT: Adding more information, My requirement is that the caller provide a SHA digest to the main function as a string on command line and the main function internally save it in the digest. SHA digest can be best represented using a unsigned char.

    Now the catch is that I can't change the signature of the main function (** char) because the main function parses other arguments which it requires as char* and not unsigned char*.

  • Rajiv
    Rajiv almost 13 years
    Yeah, thats the problem, how do I solve the incompatibility in a better way?
  • Oliver Charlesworth
    Oliver Charlesworth almost 13 years
    IMO, introducing a dummy variable here just obfuscates the code, with no corresponding benefit.
  • noelicus
    noelicus almost 13 years
    If you could tell us why you need in as an unsigned char, that might help us answer? To take a guess at a better solution you maybe should be using a structure or union instead of a blob of unsigned char memory.
  • pmg
    pmg almost 13 years
    The OP apparently wants a "better way than a cast". The obfuscated (void*) variable accomplishes a different way: I'll leave the decision if it's better to the OP (like you, @Oli, I think it isn't).
  • pmg
    pmg almost 13 years
    You have no guarantee accessing argv[2][19] is allowed.
  • pmg
    pmg almost 13 years
    With memcpy, you first need to check the length of argv[2] to avoid accessing elements outside the array.
  • pmg
    pmg almost 13 years
    I'm not sure the '\0' is needed in digest. Anyway, now you need to check that strlen(argv[2]) is small enough for the size allocated for digest :)
  • cyber_raj
    cyber_raj almost 13 years
    @pmg hmm...then OP have to synchronize the allocation size for digest with the (strlen (argv[2]) + 1) * sizeof (unsigned char)
  • R.. GitHub STOP HELPING ICE
    R.. GitHub STOP HELPING ICE almost 13 years
    In the case of char * vs unsigned char *, the warning (which, per the standard, the compiler is supposed to treat as an error!) is rarely indicative of any bug except a bug in the standard. Almost all of the standard functions take char * but deal with data which is really treated as an array of unsigned char. See strcmp.
  • Oliver Charlesworth
    Oliver Charlesworth almost 13 years
    @R..: What do you mean "treated as an array of unsigned char"?
  • R.. GitHub STOP HELPING ICE
    R.. GitHub STOP HELPING ICE almost 13 years
    I gave strcmp as an example. It's required to make its comparison based on the difference between the first non-matching bytes interpreted as unsigned char.
  • R.. GitHub STOP HELPING ICE
    R.. GitHub STOP HELPING ICE almost 13 years
    There are also issues with the fact that, on a non-twos-complement implementation where char is signed, the value 0 could have two representations, while only the all-bits-0 byte is the null terminator. This means any function that deals with null terminated strings on such an implementation must be dealing with them as unsigned char [] in order to tell the difference. Admittedly, any non-twos-complement implementation where plain char is signed would be rather stupid to begin with though...
  • quickly_now
    quickly_now over 9 years
    On some strange machines, sizeof(char) may not be 1. eg TMS320C40. Showing my age here.