将 char* 转换为 unsigned char*

Posted

技术标签:

【中文标题】将 char* 转换为 unsigned char*【英文标题】:Converting char* to unsigned char* 【发布时间】:2011-10-19 21:24:59 【问题描述】:

如何在 C 中正确地将 char* 复制到 unsigned char*。以下是我的代码

int main(int argc, char **argv)

    unsigned char *digest;

    digest = malloc(20 * sizeof(unsigned char));
    strncpy(digest, argv[2], 20);
    return 0;

我想正确地将 char* 数组复制到 unsigned char* 数组。我使用上面的代码收到以下警告

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

编辑:添加更多信息,我的要求是调用者在命令行上将 SHA 摘要作为字符串提供给主函数,并且主函数在内部将其保存在摘要中。 SHA 摘要最好用无符号字符表示。

现在的问题是我无法更改主函数的签名 (** char),因为主函数将它需要的其他参数解析为 char* 而不是 unsigned char*。

【问题讨论】:

哈希摘要通常表示为摘要的十六进制值的 ASCII 表示(例如“b6379dab2c...”)。 char 非常适合这个! @oli 所以基本上演员应该也可以正常工作,没有任何问题 strncpy((char*)digest, argv[2], 20);因为我们在处理 ASCII? @Rajiv:有两种不同的方式来表示 SHA-1 摘要,即 160 位。其中一种方法是使用 20 个 8 位字节,unsigned char 是最好的类型。另一种方法是使用 ASCII 表示,其中每个字符都是一个十六进制数字,代表 4 位,因此需要 40 个。显然strncpy 不会在它们之间转换。 @Steve:是的,我使用的是 20 个 8 位的 unsigned char 版本。如果 strncpy 不能, memcpy 或任何其他函数都可以解决问题? @Rajiv:您认为用户将如何在终端输入这些 8 位值?如果其中一个是 0 怎么办? 【参考方案1】:

为避免编译器警告,您只需要:

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

但避免编译器警告通常不是一个好主意;它告诉你存在根本的不兼容。在这种情况下,不兼容之处在于 char 的范围是 -128 到 +127(通常),而 unsigned char 的范围是 0 到 +255。

【讨论】:

是的,就是这个问题,如何更好地解决不兼容问题? 如果您能告诉我们为什么您需要 in 作为无符号字符,这可能有助于我们回答吗?要猜测更好的解决方案,您可能应该使用结构或联合,而不是无符号字符内存块。 char *unsigned char * 的情况下,警告(根据标准,编译器应该将其视为错误!)除了标准。几乎所有标准函数都采用char *,但处理的数据实际上被视为unsigned char 的数组。见strcmp @R..:“被视为unsigned char 的数组”是什么意思? 我以strcmp为例。需要根据第一个不匹配字节之间的差异进行比较解释为unsigned char【参考方案2】:

您无法正确复制它,因为类型不同,编译器会警告您。

如果您需要复制argv[2] 数组的原始位,您应该使用memcpy 函数。

【讨论】:

使用memcpy,首先需要检查argv[2]的长度,避免访问数组外的元素。【参考方案3】:

strncpy() 调用中放弃签名

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

或引入另一个变量

#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;


还要注意malloc(20 * sizeof(unsigned char*)) 可能不是您想要的。我想你想要malloc(20 * sizeof(unsigned char)),或者,根据定义,sizeof (unsigned char)1malloc(20)。 如果您真的想在调用中使用每个元素的大小,请使用对象本身,就像我上面的代码一样。

【讨论】:

IMO,这里引入一个虚拟变量只是混淆了代码,没有相应的好处。 OP 显然想要一个“比演员阵容更好的方法”。混淆的 (void*) 变量以不同的方式完成:如果它更好,我将把决定留给 OP(就像你一样,@Oli,我认为不是)。【参考方案4】:

您可以将 memcpy 用作:

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

因为 src 和 dest 指针指向的对象的底层类型与此函数无关。

【讨论】:

你不能保证访问argv[2][19]是被允许的。 我不确定digest 中是否需要'\0'。无论如何,现在您需要检查 strlen(argv[2]) 是否足够小以适应分配给 digest 的大小:) @pmg hmm...那么 OP 必须将摘要的分配大小与 (strlen (argv[2]) + 1) * sizeof (unsigned char) 同步 在一些奇怪的机器上,sizeof(char)可能不是1。例如TMS320C40。在这里显示我的年龄。【参考方案5】:

没有一种方法可以将char * 转换为unsigned char *。它们指向数据,你必须知道数据的格式。

SHA-1 哈希至少有 3 种不同的格式:

原始二进制摘要作为正好 20 个八位字节的数组 摘要为十六进制字符串,如"e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4" 作为 Base64 字符串的摘要,例如 "5en6G6MezRroT3XKqkdPOmY/BfQ="

您的malloc(20 * sizeof(unsigned char)) 具有二进制摘要的确切大小,但太小而无法容纳十六进制字符串或 Base64 字符串。我猜unsigned char * 指向一个二进制摘要。

但是char * 来自main() 的命令行参数,所以char * 可能指向一个字符串。命令行参数总是 C 字符串;它们以 NUL 终止符 '\0' 结尾,并且永远不会在字符串中包含 '\0'。原始二进制摘要可能包含 '\0',因此它们不能用作命令行参数。

将 SHA-1 摘要从十六进制字符串转换为原始二进制的代码可能如下所示

#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;

不要使用strncpy(dst, src, 20) 复制原始二进制摘要。 strncpy(3) 函数在找到'\0' 时停止复制;所以如果你的摘要包含'\0',你会丢失部分摘要。

【讨论】:

【参考方案6】:

只要把(char*)放在前面 或(unsigned char*)

【讨论】:

【参考方案7】:

警告就是它所说的,您正在将一个 unsigned char * 摘要传递给 strncpy 函数,该函数的符号与预期的不同。

【讨论】:

以上是关于将 char* 转换为 unsigned char*的主要内容,如果未能解决你的问题,请参考以下文章

如何将 unsigned char[] 转换为 std::vector<unsigned char>

如何将 unsigned long long int 转换为 unsigned char*?

将 unsigned char 转换为 signed char 以获得红黑树

将 unsigned int + 字符串转换为 unsigned char 向量

如何将 unsigned char* 转换为 unsigned long long int?

C++怎么将 CString 转换成 unsigned char 的数组