2011-08-04 128 views
18

如何与char * 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 *阵列。添加更多的信息,我的要求是,来电者提供一个SHA消化的主要功能是在命令行的字符串和主要功能内部保存:我用上面的代码

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

编辑收到以下警告它在消化。 SHA摘要最好用一个无符号字符表示。

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

+2

散列摘要通常表达为摘要十六进制值的ASCII表示(例如“b6379dab2c ...”)。一个'char'对此绝对好! –

+0

@oli所以基本上演员也应该没有任何问题strncpy((char *)digest,argv [2],20)正常工作;因为我们正在处理ASCII? – Rajiv

+0

@Rajiv:有两种不同的方式来表示一个SHA-1摘要,它是160位。其中一种方法是使用20个8位字节,'unsigned char'是最好的类型。另一种方法是使用ASCII表示法,其中每个字符都是十六进制数字,代表4位,因此需要其中的40位。显然'strncpy'不会在它们之间进行转换。 –

回答

10

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

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

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

+0

是的,那是问题,我如何以更好的方式解决不兼容问题? – Rajiv

+0

如果你可以告诉我们为什么你需要在一个无符号的字符,这可能会帮助我们回答?要猜测更好的解决方案,您可能应该使用结构或联合而不是一堆unsigned char内存。 – noelicus

+0

在'char *'vs'unsigned char *'的情况下,警告(根据标准,编译器应该视为错误!)除了标准中的错误外,很少表示任何错误。几乎所有的标准函数都使用'char *',但处理的数据实际上被当作一个'unsigned char'数组来处理。请参阅'strcmp'。 –

4

你不能正确复制它,因为类型有差异,编译器会警告你。

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

+0

对于'memcpy',首先需要检查'argv [2]'的长度,以避免访问阵列外部的元素。 – pmg

+0

@pmg毫无疑问! –

0

警告就是这么说的,你正在传递一个无符号的char *摘要给strncpy函数,它与它所期望的不同。

2

演员的符号性消失在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)1,malloc(20)。 如果您确实想使用调用中每个元素的大小,请使用该对象本身,就像在上面的代码中一样。

+1

国际海事组织,在这里引入一个虚拟变量只是混淆了代码,没有相应的好处。 –

+0

OP显然想要一个“比演员更好的方式”。混淆的'(void *)'变量实现了一种不同的方式:如果对OP更好,我会留下决定(就像你,@Oli,我认为它不是)。 – pmg

1

您可以使用memcpy为:

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

为基础类型的对象指向src和dest中的指针是无关此功能。

+0

您不能保证访问'argv [2] [19]'是允许的。 – pmg

+0

@pmg编辑过你很好关注 –

+0

我不确定''\ 0''是否需要在'digest'中。无论如何,现在你需要检查'strlen(argv [2])'是否足够小,以便分配给'摘要'的大小:) – pmg

0

没有办法将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',因此它们不能用作命令行参数。

转换一个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',则会丢失部分摘要。