2011-08-04 135 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',則會丟失部分摘要。