Rajiv
Rajiv

Reputation: 565

Converting char* to unsigned char*

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*.

Upvotes: 22

Views: 51469

Answers (7)

Johnny camargo
Johnny camargo

Reputation: 11

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

Upvotes: 1

George Koehler
George Koehler

Reputation: 1703

There is no one way to convert char * to unsigned char *. They point to data, and you must know the format of the data.

There are at least 3 different formats for a SHA-1 hash:

  • the raw binary digest as an array of exactly 20 octets
  • the digest as a hexadecimal string, like "e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4"
  • the digest as a Base64 string, like "5en6G6MezRroT3XKqkdPOmY/BfQ="

Your malloc(20 * sizeof(unsigned char)) has the exact size of a binary digest, but is too small to fit a hexadecimal string or a Base64 string. I guess that the unsigned char * points to a binary digest.

But the char * came from the command-line arguments of main(), so the char * probably points to a string. Command-line arguments are always C strings; they end with the NUL terminator '\0' and never contain '\0' in the string. Raw binary digests might contain '\0', so they don't work as command-line arguments.

The code to convert a SHA-1 digest from hexadecimal string to raw binary might look like

#include <stdio.h>
#include <stdlib.h>

unsigned char *
sha1_from_hex(char *hex)
{
    int i, m, n, octet;
    unsigned char *digest;

    digest = malloc(20);
    if (!digest)
        return NULL;

    for (i = 0; i < 20; i++) {
        sscanf(hex, " %n%2x%n", &m, &octet, &n);
        if (m != 0 || n != 2)
            goto fail;
        digest[i] = octet;
        hex += 2;
    }
    if (*hex)
        goto fail;
    return digest;

fail:
    free(digest);
    return NULL;
}

Don't use strncpy(dst, src, 20) to copy raw binary digests. The strncpy(3) function stops copying if it finds a '\0'; so if your digest contains '\0', you lose part of the digest.

Upvotes: 1

Sandeep Pathak
Sandeep Pathak

Reputation: 10747

Warning is simply what it says , you are passing an unsigned char * digest to strncpy function which is in different signedness from what it expects.

Upvotes: 0

cyber_raj
cyber_raj

Reputation: 1857

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.

Upvotes: 1

pmg
pmg

Reputation: 108978

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.

Upvotes: 2

Oliver Charlesworth
Oliver Charlesworth

Reputation: 272657

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.

Upvotes: 15

pabdulin
pabdulin

Reputation: 35235

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.

Upvotes: 6

Related Questions