如何将 char 数组转换为结构?

Posted

技术标签:

【中文标题】如何将 char 数组转换为结构?【英文标题】:How to cast a char array into a structure? 【发布时间】:2021-09-05 18:01:25 【问题描述】:

我正在尝试将 RSA 私钥从文件读取到结构中。我正在使用mpi_read_string() 将这些密钥加载到 RSA 上下文中。因此,每个单独的键都必须以空值结尾。为了在从文件中读取每个键时实现这一点,我在每个键的末尾连接\0

综上,我将文件的所有内容读入unsigned char * buffer,对每一行进行标记,在每行末尾连接\0,并将其存储到unsigned char no_label_key_array[]。我也有一个结构struct RSA_KEY。我正在尝试将此unsigned char no_label_key_array[] 分配到结构中。

rsa_priv.txt 包含以下内容,

N = D0C2ACDCF780B1E4846054BDA700F18D567247FE8BC5BA4FBCAB814E619DA63A20F65A58EE89FC0824DC9367C5725BDDC596065F1C8868E99C896F3A0CF7D7F0A785E668F2568F19BAFB8FF3BA5CDF487544EFE71010BEDB4EE16EDC3AF0A71391AD3194B42D3FD40B4E0DE12A22D8188AF03FF4E36D37BA1DA1F3C57188E60DA38C25329E48805FC7FF524761A6F010E737B927D8F67383274F8E600167A52A042E1DCA3335150C090803F9D96F6E63BEBFB153516E863F5B4CB02104077834FC5EC31A47451783931D643CE736DD1BAB40C5523858BB067FB9E490DCB5FDBBB03B9D68A8998C1347E237C477AA14B0997A84708CED05A9E24C7072B838F753
E = 010001
D = 21AFE07431CE47269083F8F8B7ABCBCEDA6DCB975457BE6662942C64091586FEE755C9A3832EAA0868665DB507A41A15F1EDF12E44ECF03D0E61111D457D730FA700D0FB0B6C13607C0F5F1DDDEB61AE9019E53A9C998F2AD5924430EEA3E9DA1B0E5F2B575DDBE86C4096B5C87661F7A7E7F7F21D0701509BBA881B4AE463F6F18C7F04AB742319E2D7319EECA136EEB0CF7B2BFA87E3A0E69FBC0E5FDC7EE6271EB2CA09DDBF7C8B57D951762708D76890E62858C1D5FC5B7E40D50913CE7797BD80F6A398FB92703FBDD33FBCB129B86E54F13EC14DA68BE139634DD1E9C01F01751C427B029AF629EED23C99726F0A0C3CEA1229E4099B588CE676975D25
P = FD1120F3E183DF72779B9B4A29FF9157C89FF8204988B6FB1211642B4D59B6A1BB306E81C040F0F822B41765FC4435A46B5090700E72B9720481EACF3624885D7A263CAC0CA559954E9382FCC7D57221CD9394C64585653664976174CAE2E7DC6A7B03DE09599B5D9501927ACC4EED5F5CBC5870E31A051AF9842945A0168E35
Q = D32E15E032B256C7DE0BDB585379EB897343ABFB8C7A86A3D798C13AE3E3F048A50DA9D7C31EB65A588CF6B9911F7B41D6F154F99B4F64839E110C30BA4B79286A4A3A3F7F0169A1D3A21F0D084CFA423E04C90C5966AC391A47F10E823C71B9716856B05BC12160DF0BA96300F8ADDC0D59E54E9CBDC7AC0EA6747DBA46C067
DP = 2004DECA7CAA16C780E2AB4F42E91716A847B53940948FB24CA2EEAD9BE7D1F7BC9B701FF29744E5E05E30E7B2775EE222C1DAC492CF692F47EAB82EE786CFCA23FE5A86DA42C186E69E3B608858354C999A26A4BF7F1543408EF6C1B439E9643604C2848162590A0A245CC834B977C72D10979010EBE5E177D884F04E450C51
DQ = 9A035E48E8305041EB9AD21994A7B233C8306E59429689632C7567573FA4993521CAD93756422BD3B008FE574F939A1CE659931387455B94F1CE950964946E841F208B628B89C83411588734C5FCFDF719ABFBC459DF1B7379CB45EEC2E4BA3BF88D93CB82DF532C86FEC646420B1B21054BAE84AAA36DDFF9BF43EDFDD063B9
QP = E7A5BC150E6A20E52920C6F24FC872B1893ED9268AA506D86EC3AA6E3B377E5F6AE0D686751CE40F684435C6F64F31888861389CE430FB271EE81D0067ED8A1BD8096FB3E4AF5839383F26F99916EED4D80CFA9B5901350A9C0AAD4E348EBCC559F92434C71DA864C13371626D9F29998748BB3C47BED31471B73ABF2E27B983

我有以下代码,

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

#define KEY_LEN 256

typedef struct RSA_KEY
    unsigned char N[KEY_LEN];
    unsigned char E[KEY_LEN];
    unsigned char D[KEY_LEN];
    unsigned char P[KEY_LEN];
    unsigned char Q[KEY_LEN];
    unsigned char DP[KEY_LEN];
    unsigned char DQ[KEY_LEN];
    unsigned char QP[KEY_LEN];
RSA_, *RSA_PTR;


int main()

    int j;
    unsigned char * buffer = 0;
    long length;
    FILE * fp = fopen ("rsa_priv.txt", "rb");

    if (fp)
        fseek (fp, 0, SEEK_END);
        length = ftell (fp);
        fseek (fp, 0, SEEK_SET);
        buffer = calloc (1,length+1);
        if (buffer)
            fread (buffer, 1, length, fp);
        
        fclose (fp);
    


    // removing label from the keys
    // tokenize key and read into rsa context
    const char s[3] = "= ";
    char *token;
    int k=0, size_tok;

    char n='\0';

    // following buffer will hold the private key without any level
    unsigned char *final_token= calloc(1, length+1);

    // get the first token
    token = strtok(buffer, s);

    // walk through other tokens
    while( token != NULL ) 
        size_tok = strlen(token);

        switch (k) 
            case 1: 
                strncat(token, &n,1);
                strcat(final_token,token);
                break;

            case 3:
                strncat(token, &n,1);
                strcat(final_token,token);
                break;

            case 5:
                strncat(token, &n,1);
                strcat(final_token,token);
                break;

            case 7:
                strncat(token, &n,1);
                strcat(final_token,token);
                break;

            case 9:
                strncat(token, &n,1);
                strcat(final_token,token);
                break;

            case 11:
                strncat(token, &n,1);
                strcat(final_token,token);
                break;

            case 13:
                strncat(token, &n,1);
                strcat(final_token,token);
                break;

            case 15:
                strncat(token, &n,1);
                strcat(final_token,token);
                break;
        
        k=k+1;
        token = strtok(NULL, "= \n");
    

    //printf("RSA keys without label \n %s",final_token);


    // coping final token to a char array,
    unsigned char no_label_key_array[strlen(final_token)];
    memcpy(no_label_key_array,final_token,sizeof(no_label_key_array));
    //printf("no_label_key_array \n %s",no_label_key_array);


    // assigning char array to a structure
    RSA_PTR rsa_ptr;
    rsa_ptr = (RSA_PTR)no_label_key_array;

    printf("rsa_ptr.N--> %s\n",rsa_ptr->N);
    printf("\n");
    printf("rsa_ptr.E--> %s\n",rsa_ptr->E);
    printf("\n");
    printf("rsa_ptr.DQ--> %s\n",rsa_ptr->DQ);
    printf("\n");
    printf("rsa_ptr.QP--> %s\n",rsa_ptr->QP);

    return 0;

此代码生成以下输出:

rsa_ptr.N - > D0C2ACDCF780B1E4846054BDA700F18D567247FE8BC5BA4FBCAB814E619DA63A20F65A58EE89FC0824DC9367C5725BDDC596065F1C8868E99C896F3A0CF7D7F0A785E668F2568F19BAFB8FF3BA5CDF487544EFE71010BEDB4EE16EDC3AF0A71391AD3194B42D3FD40B4E0DE12A22D8188AF03FF4E36D37BA1DA1F3C57188E60DA38C25329E48805FC7FF524761A6F010E737B927D8F67383274F8E600167A52A042E1DCA3335150C090803F9D96F6E63BEBFB153516E863F5B4CB02104077834FC5EC31A47451783931D643CE736DD1BAB40C5523858BB067FB9E490DCB5FD21AFE07431CE47269083F8F8B7ABCBCEDA6DCB975457BE6662942C64091586FEE755C9A3832EAA0868665DB507A41A15F1EDF12E44ECF03D0E61111D457D730FA700D0FB0B6C13607C0F5F1DDDEB61AE9019E53A9C998F2AD5924430EEA3E9DA1B0E5F2B575DDBE86C4096B5C87661F7A7E7F7F21D0701509BBA881B4AE463F6F18C7F04AB742319E2D7319EECA136EEB0CF7B2BFA87E3A0E69FBC0E5FDC7EE6271EB2CA09DDBF7C8B57D951762708D76890E62858C1D5FC5B7E40D50913CE7797BD80F6A398FB92703FBDD33FBCB129B86E54F13EC14DA68BE139634DD1E9C01F01751C427FD1120F3E183DF72779B9B4A29FF9157C89FF8204988B6FB1211642B4D59B6A1BB306E81C040F0F 822B41765FC4435A46B5090700E72B9720481EACF3624885D7A263CAC0CA559954E9382FCCD32E15E032B256C7DE0BDB585379EB897343ABFB8C7A86A3D798C13AE3E3F048A50DA9D7C31EB65A588CF6B9911F7B41D6F154F99B4F64839E110C30BA4B79286A4A3A3F7F0169A1D3A21F0D02004DECA7CAA16C780E2AB4F42E91716A847B53940948FB24CA2EEAD9BE7D1F7BC9B701FF29744E5E05E30E7B2775EE222C1DAC492CF692F47EAB82EE786CFCA23FE5A86DA42C186E69E3B6089A035E48E8305041EB9AD21994A7B233C8306E59429689632C7567573FA4993521CAD93756422BD3B008FE574F939A1CE659931387455B94F1CE950964946E841F208B628B89C83411588734CE7A5BC150E6A20E52920C6F24FC872B1893ED9268AA506D86EC3AA6E3B377E5F6AE0D686751CE40F684435C6F64F31888861389CE430FB271EE81D0067ED8A1BD8096FB3E4AF5839383F26F99916EED4D80CFA9B5901350A9C0AAD4E348EBCC559F92434C71DA864C13371626D9F29998748BB3C47BED31471B73ABF2E27B983 P>

rsa_ptr.E - > A38C25329E48805FC7FF524761A6F010E737B927D8F67383274F8E600167A52A042E1DCA3335150C090803F9D96F6E63BEBFB153516E863F5B4CB02104077834FC5EC31A474521AFE07431CE47269083F8F8B7ABCBCEDA6DCB975457BE6662942C64091586FEE755C9A3832EAA0868665DB507A41A15F1EDF12E44ECF03D0E61111D457D730FA700D0FB0B6C13607C0F5F1DDDEB61AE9019E53A9C998F2AD5924430EEA3E9DA1B0E5F2B575DDBE86C4096B5C87661F7A7E7F7F21D0701509BBA881B4AE463F6F18C7F04AB742319E2D7319EECA136EEB0CF7B2BFA87E3A0E69FBC0E5FDC7EE6271EB2CA09DDBF7C8B57D951762708D76890E62858C1D5FC5B7E40D50913CE7797BD80F6A398FB92703FBDD33FBCB129B86E54F13EC14DA68BE139634DD1E9C01F01751C427FD1120F3E183DF72779B9B4A29FF9157C89FF8204988B6FB1211642B4D59B6A1BB306E81C040F0F822B41765FC4435A46B5090700E72B9720481EACF3624885D7A263CAC0CA559954E9382FCCD32E15E032B256C7DE0BDB585379EB897343ABFB8C7A86A3D798C13AE3E3F048A50DA9D7C31EB65A588CF6B9911F7B41D6F154F99B4F64839E110C30BA4B79286A4A3A3F7F0169A1D3A21F0D02004DECA7CAA16C780E2AB4F42E91716A847B53940948FB24CA2EEAD9BE7D1F7BC9B701FF29744E 5E05E30E7B2775EE222C1DAC492CF692F47EAB82EE786CFCA23FE5A86DA42C186E69E3B6089A035E48E8305041EB9AD21994A7B233C8306E59429689632C7567573FA4993521CAD93756422BD3B008FE574F939A1CE659931387455B94F1CE950964946E841F208B628B89C83411588734CE7A5BC150E6A20E52920C6F24FC872B1893ED9268AA506D86EC3AA6E3B377E5F6AE0D686751CE40F684435C6F64F31888861389CE430FB271EE81D0067ED8A1BD8096FB3E4AF5839383F26F99916EED4D80CFA9B5901350A9C0AAD4E348EBCC559F92434C71DA864C13371626D9F29998748BB3C47BED31471B73ABF2E27B983 P>

2004DECA7CAA16C780E2AB4F42E91716A847B53940948FB24CA2EEAD9BE7D1F7BC9B701FF29744E5E05E30E7B2775EE222C1DAC492CF692F47EAB82EE786CFCA23FE5A86DA42C186E69E3B6089A035E48E8305041EB9AD21994A7B233C8306E59429689632C7567573FA4993521CAD93756422BD3B008FE574F939A1CE659931387455B94F1CE950964946E841F208B628B89C83411588734CE7A5BC150E6A20E52920C6F24FC872B1893ED9268AA506D86EC3AA6E3B377E5F6AE0D686751CE40F684435C6F64F31888861389CE430FB271EE81D0067ED8A1BD8096FB3E4AF5839383F26F99916EED4D80CFA9B5901350A9C0AAD4E348EBCC559F92434C71DA864C13371626D9F29998748BB3C47BED31471B73ABF2E27B983 P>

9A035E48E8305041EB9AD21994A7B233C8306E59429689632C7567573FA4993521CAD93756422BD3B008FE574F939A1CE659931387455B94F1CE950964946E841F208B628B89C83411588734CE7A5BC150E6A20E52920C6F24FC872B1893ED9268AA506D86EC3AA6E3B377E5F6AE0D686751CE40F684435C6F64F31888861389CE430FB271EE81D0067ED8A1BD8096FB3E4AF5839383F26F99916EED4D80CFA9B5901350A9C0AAD4E348EBCC559F92434C71DA864C13371626D9F29998748BB3C47BED31471B73ABF2E27B983 P>

抱歉,我无法将输出格式化为单个块。

从输出中,我可以看到即使在连接\0 之后我的输出也不正确?

所以我的问题是,我是否正确连接?我可以像我一样将无符号字符数组转换为结构吗?如果没有,我该怎么做?

【问题讨论】:

确实知道可以在switch 中组合多个case 标签?如case 1: case 3: case 5: /* Do something common for all cases... */ break; @Someprogrammerdude,我现在这样做。感谢您的建议。 N = ...E = ... 等是否保证是文件中的单独行? @Zoso,是的。它们将始终位于单独的一行中。 好吧,你还假设KEY_LEN 是256,而N 的值是512 len。这是疏忽吗? 【参考方案1】:

你有几个错误:

您在这里没有正确使用字符串:unsigned char no_label_key_array[strlen(final_token)]; 这是一个非常常见的常见问题解答,我们几乎每天都会收到。请阅读How should character arrays be used as strings? rsa_ptr = (RSA_PTR)no_label_key_array 是一个严格的别名违规。你不能像这样在类型之间疯狂转换。 What is the strict aliasing rule? 解决方案是将您的结构与一个与结构相同大小的原始unsigned char 数组放在一个联合中。

其他问题:

将指针隐藏在typedef 后面是非常糟糕的做法。它完全没有任何作用,只是让你的代码更难阅读。 RSA* 是理想的 C 代码,typedef RSA_PTR 只会让情况变得更糟。

switch 可以替换为查找表,以减少代码重复,提高可读性和性能,如下所示:

  unsigned int k; // needs to be unsigned
  const bool accepted [16] =
  
    [ 1] = true, [ 3] = true, [ 5] = true,  [ 7] = true,
    [ 9] = true, [11] = true, [13] = true,  [15] = true,
  ;
  ... // assign something to k   

  if(k<16 && accepted[k]) // replace the whole switch with this
  
    strncat(token, &n,1);
    strcat(final_token,token);
  

【讨论】:

以上是关于如何将 char 数组转换为结构?的主要内容,如果未能解决你的问题,请参考以下文章

将 char 数组转换为结构指针

如何将char数组转换为CString

如何将字符串数组转换为 Char * 数组 c++

如何将char数组转换为字节数组?

如何将 char 数组转换为 wchar_t 数组?

如何将 String 转换为 char 数组?