Reputation: 565
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
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:
"e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4"
"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
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
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
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
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
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