如何将char转换为unsigned int?

时间:2018-08-12 03:03:43

标签: c struct floating-point int unions

程序的工作方式

./my program 1 10000100 01000000001000001000000
// Reads the argv's
// Converts them into unsigned ints

如何将char *转换为unsigned int?我以为我使用了位操作,但是在将char转换为unsigned int时有点迷失了。

代码。

struct _float {
    unsigned int sign:1, exp:8, frac:23;
};

union _bits32 {
    float    fval;  // Bits as a float
    Word     xval;  // Bits as a word
    Float32 bits;  // manipulate individual bits
};

union _bits32 getBits(char *sign, char *exp, char *frac);

int main(int argc, char **argv) {
    u = getBits(argv[1], argv[2], argv[3]);
    return 0;
}

// Here I am converting the char's into unsigned ints
union _bits32 getBits(char *sign, char *exp, char *frac) {
    Union32 new;

    // convert char *sign into a single bit in new.bits
    new.bits.sign = *sign;

    // convert char *exp into an 8-bit value in new.bits
    new.bits.exp = *exp;

    // convert char *frac into a 23-bit value in new.bits
    new.bits.frac = *frac;

    return new;
}

4 个答案:

答案 0 :(得分:1)

因此,您需要读取每个位(每个位1个字符),并将其保存为正确位位置的整数。这是一个函数,它可以对不超过32位的任意长度执行此操作。

// Takes in the string with the bits (e.g. "01010100011")
// Returns the integer represented by those bits (leading bits are 0's)
int parseFromBinary(char* bitString) {
  int val = 0;
  int i = 0;
  // While there are more characters
  while (bitString[i] != 0) {
    // Shift everything left (multiply by 2) to make room for the new bit
    val <<= 1;
    // Add the new bit (no effect if it is a 0)
    val |= bitString[i] - '0';
    i++;
  }
  return val;
}

您确实希望为每个字段调用一次此函数,尽管实际上不必循环1个符号位,这无疑会使事情变得不太清楚。

答案 1 :(得分:0)

#include <stdio.h>
int main ( int argc, char *argv[])
{
    unsigned int ra,rb;

    if(argc<2) return(1);

    rb=0;
    for(ra=0;argv[1][ra];ra++)
    {
        rb<<=1;
        rb|=argv[1][ra]&1;
    }
    printf("0x%08X\n",rb);
    return(0);
}

构建并运行

gcc so.c -o so
./so 000100000
0x00000020
./so 101010101
0x00000155
./so 010101010
0x000000AA
./so 101
0x00000005

运行时,字符串“ 101”如下所示:

argv[1]={0x31,0x30,0x31};

因为它是ASCII。 (google ASCII图表并转到图像)

所需结果是值为0b101,即0x5或十进制5。

通常您要解析该字符串

argv[1][0]=0x31;
argv[1][1]=0x30;
argv[1][2]=0x31;
argv[1][3]=0x00;

从字符串0x31的第一个字节开始,需要提取lsbit并将其保存。这是我们最终编号的0b1xx位,我们可以将其视为人类,但需要获取程序才能执行。当转到下一个字节时,如果将累加器左移并为下一位腾出空间,您将以0b10结尾,而orr为零,最后以0b10结尾,这是我们最终答案的这两位0b10x 现在将0b10左移,为下一位腾出空间,从ascii字节中获取该位,得到0b101。只要您在变量中有空间,就可以重复此操作。

因为从左到右的字符串顺序是数组项0、1、2、3。这些以二进制值的顺序与msbit到lsbit对齐,我们要提取数组中的第一个字节是我们的msbit,因此,如果在添加更多位时继续向左移动,则msbit会在左侧结束根据需要添加最后一位,即字符串中的最后一个字节,完成后将为lsbit。

编辑

#include <stdio.h>

int main ( int argc, char *argv[])
{
    unsigned int ra,rb;

    if(argc<2) return(1);

    rb=0;
    for(ra=0;argv[1][ra];ra++)
    {
        rb<<=1;
        rb|=argv[1][ra]&1;
    }
    //printf("0x%08X\n",rb);
    printf("0b");
    for(ra=0x80000000;ra;ra>>=1)
    {
        if(ra&rb) printf("1"); else printf("0");
    }
    printf("\n");
    return(0);
}

给予

./so 101
0b00000000000000000000000000000101
./so 101010101
0b00000000000000000000000101010101
./so 111000111000
0b00000000000000000000111000111000

EDIT2

您确实必须了解二进制,ASCII,视觉表示,位操作等。

#include <stdio.h>

int main ( int argc, char *argv[])
{
    unsigned int ra,rb;

    if(argc<2) return(1);

    rb=0;
    for(ra=0;argv[1][ra];ra++)
    {
        rb<<=1;
        rb|=argv[1][ra]&1;
    }
    printf("hex %08X\n",rb);
    printf("octal %011o\n",rb);
    printf("binary ");
    for(ra=0x80000000;ra;ra>>=1)
    {
        if(ra&rb) printf("1"); else printf("0");
    }
    printf("\n");
    return(0);
}

给予

./so 101010101
hex 00000155
octal 00000000525
binary 00000000000000000000000101010101
./so 111000111
hex 000001C7
octal 00000000707
binary 00000000000000000000000111000111
./so 101
hex 00000005
octal 00000000005
binary 00000000000000000000000000000101

这些二进制位

000111000111

为了使它们更易于阅读和交流,可以分为八进制:

000 111 000 111

从右边开始,一次取三个,这将得到0707

或者十六进制,从右开始,一次取四个

0001 1100 0111 

这给出1C7

但是为了“看到”它们,计算机又回到了ASCII(这一天和时代被转换成更大的表示形式,包括语言差异)

我手动将二进制数字0101转换为0x31,0x30,0x31,因此我们可以看到“ 101”。格式化的printf 0101变为0x35,因此我们可以看到“ 5”,同样,二进制数0101也变为0x30,0x35,因此我们可以看到“ 05”。

EDIT3

#include <stdio.h>

int main ( int argc, char *argv[])
{
    unsigned int ra,rb;

    if(argc<2) return(1);

    rb=0;
    for(ra=0;argv[1][ra];ra++)
    {
        rb<<=1;
        rb|=argv[1][ra]&1;
    }
    printf("binary (base 2) ");
    for(ra=0x80000000;ra;ra>>=1)
    {
        char rc;
        if(ra&rb) rc=0x31; else rc=0x30;
        printf("%c",rc);
    }
    printf("\n");
    printf("base four ");
    for(ra=30;;ra-=2)
    {
        char rc;
        rc=(rb>>ra)&3;
        rc+=0x30;
        printf("%c",rc);
        if(ra==0) break;
    }
    printf("\n");
    printf("octal (base 8) ");
    for(ra=30;;ra-=3)
    {
        char rc;
        rc=(rb>>ra)&7;
        rc+=0x30;
        printf("%c",rc);
        if(ra==0) break;
    }
    printf("\n");
    printf("hexadecimal (base 16) ");
    for(ra=28;;ra-=4)
    {
        char rc;
        rc=(rb>>ra)&0xF;
        rc+=0x30;
        if(rc>0x39) rc+=7;
        printf("%c",rc);
        if(ra==0) break;
    }
    printf("\n");

    return(0);
}

./so 101
binary (base 2) 00000000000000000000000000000101
base four 0000000000000011
octal (base 8) 00000000005
hexadecimal (base 16) 00000005
./so 1010
binary (base 2) 00000000000000000000000000001010
base four 0000000000000022
octal (base 8) 00000000012
hexadecimal (base 16) 0000000A
./so 11001100
binary (base 2) 00000000000000000000000011001100
base four 0000000000003030
octal (base 8) 00000000314
hexadecimal (base 16) 000000CC
./so 111000111
binary (base 2) 00000000000000000000000111000111
base four 0000000000013013
octal (base 8) 00000000707
hexadecimal (base 16) 000001C7
./so 111100001111
binary (base 2) 00000000000000000000111100001111
base four 0000000000330033
octal (base 8) 00000007417
hexadecimal (base 16) 00000F0F

编辑

#include <stdio.h>
int main ( void )
{
    unsigned int ra;
    unsigned int rb;
    unsigned int rc;
    char s[32];
    rb=0x1234;
    for(ra=0x8000;ra;ra>>=1)
    {
        printf("0x%04X & 0x%04X = 0x%04X ",ra,rb,ra&rb);
        if(ra&rb) printf("1"); else printf("0");
        printf("\n");
    }
    for(ra=0x8000;ra;ra>>=1)
    {
        if(ra&rb) printf("1"); else printf("0");
    }
    printf("\n");
    for(ra=0;ra<16;ra++)
    {
        if((ra&3)==0) printf(" ");
        if((rb>>(15-ra))&1) printf("1"); else printf("0");
    }
    printf("\n");
    for(rc=0,ra=0x8000;ra;ra>>=1,rc++)
    {
        if(ra&rb) s[rc]='1'; else s[rc]='0';
    }
    s[rc++]='\r';
    s[rc++]='\n';
    s[rc]=0;
    for(ra=0;s[ra];ra++)
    {
        printf("0x%02X ",s[ra]);
    }
    printf("\n");
    printf("%s",s);
    return(0);
}

输出

0x8000 & 0x1234 = 0x0000 0
0x4000 & 0x1234 = 0x0000 0
0x2000 & 0x1234 = 0x0000 0
0x1000 & 0x1234 = 0x1000 1
0x0800 & 0x1234 = 0x0000 0
0x0400 & 0x1234 = 0x0000 0
0x0200 & 0x1234 = 0x0200 1
0x0100 & 0x1234 = 0x0000 0
0x0080 & 0x1234 = 0x0000 0
0x0040 & 0x1234 = 0x0000 0
0x0020 & 0x1234 = 0x0020 1
0x0010 & 0x1234 = 0x0010 1
0x0008 & 0x1234 = 0x0000 0
0x0004 & 0x1234 = 0x0004 1
0x0002 & 0x1234 = 0x0000 0
0x0001 & 0x1234 = 0x0000 0
0001001000110100
 0001 0010 0011 0100
0x30 0x30 0x30 0x31 0x30 0x30 0x31 0x30 0x30 0x30 0x31 0x31 0x30 0x31 0x30 0x30 0x0D 0x0A 
0001001000110100

答案 2 :(得分:0)

除了其他答案外,“混淆”部分最有可能是由于getBits会将值存储在new.bits中并带有 reverse 位。类似于主机到网络网络到主机字节顺序,但在您的情况下完全按位反转。

您在哪里

struct _float {
    unsigned int sign:1, exp:8, frac:23;
};

您只有一个位域,将sign指定为最高有效位。在内存中,在小端架构上,这将是 bit-0 ,而不是 bit-31 ,从而导致您在{{1}的getBits中进行操作}将new.bitsnew.fval保留在内存中。

现在,当然,简单的解决方法是反转位字段,例如

new.xval

为说明这一点,让我们仅取struct _float { unsigned int frac:23, exp:8, sign:1; }; 并在返回之前反转位。没什么好想的,只是一个循环来反转无符号值的位,例如

new

此外,请注意,/* reverse the bits in v, sz number of bits */ unsigned revbits (unsigned v, int sz) { unsigned r = 0; for (int i = 0; i < sz; i++) r |= ((v >> i) & 0x1) << (sz - i - 1); return r; } 中不能将字符串分配给位域值,必须进行“或”运算并将每个单独的位移入位域中的适当位置,同时减去getBits以将ASCII转换为整数值,例如:

'0'

现在让我们反转/* convert char *exp into an 8-bit value in new.bits */ for (int i = 0; i < EXP; i++) new.bits.exp |= (exp[i] - '0') << i; 之前newgetBitsreturn的位,例如

/* convert three bit-strings (already checked)
 * into the components of a struct _float
 */
Union32 getBits (char *sign, char *exp, char *frac) {

    Union32 new = { .xval = 0 };

    /* convert char *sign into a single bit in new.bits */
    new.bits.sign = *sign - '0';

    /* convert char *exp into an 8-bit value in new.bits */
    for (int i = 0; i < EXP; i++)
        new.bits.exp |= (exp[i] - '0') << i;

    /* convert char *frac into a 23-bit value in new.bits */
    for (int i = 0; i < FRAC; i++)
        new.bits.frac |= (frac[i] - '0') << i;

    /* reverse the bit order */
    new.xval = revbits (new.xval, sizeof new.xval * CHAR_BIT);

    return new;
}

现在您的示例正确输出-40.015869。如果将所有部分放在一起,并在代码中使用常量,而不是在整个过程中撒上魔术数字,并使用CHAR_BITlimits.h确保我们拥有正确的位数,并为typedef添加Word缺少的unsigned,您可以执行以下操作:

#include <stdio.h>
#include <limits.h>

/* constants for use in code (don't use magic numbers) */
enum { SIGN = 1, EXP = 8, FRAC = 23 };

typedef struct _float {
    unsigned sign:SIGN, 
             exp :EXP, 
             frac:FRAC;
} Float32;

typedef unsigned Word;  /* you need typedef for unsigned as Word */

union _bits32 {
    float    fval;      /* Bits as a float */
    Word     xval;      /* Bits as a word  */
    Float32  bits;      /* manipulate individual bits (reverse order) */
};
typedef union _bits32 Union32;

/* reverse the bits in v, sz number of bits */
unsigned revbits (unsigned v, int sz)
{
    unsigned r = 0;

    for (int i = 0; i < sz; i++) 
        r |= ((v >> i) & 0x1) << (sz - i - 1);

    return r;
}

/* convert three bit-strings (already checked)
 * into the components of a struct _float
 */
Union32 getBits (char *sign, char *exp, char *frac) {

    Union32 new = { .xval = 0 };

    /* convert char *sign into a single bit in new.bits */
    new.bits.sign = *sign - '0';

    /* convert char *exp into an 8-bit value in new.bits */
    for (int i = 0; i < EXP; i++)
        new.bits.exp |= (exp[i] - '0') << i;

    /* convert char *frac into a 23-bit value in new.bits */
    for (int i = 0; i < FRAC; i++)
        new.bits.frac |= (frac[i] - '0') << i;

    /* reverse the bit order */
    new.xval = revbits (new.xval, sizeof new.xval * CHAR_BIT);

    return new;
}

int main (int argc, char **argv) {

    union   _bits32 u = { .xval = 0 };

    /* set u (default value is PI to 3.14159) */
    u = getBits (argc > 1 ? argv[1] : "0", 
                 argc > 2 ? argv[2] : "10000000", 
                 argc > 3 ? argv[3] : "10010010000111111010000");

    /* output fval */
    printf ("u.fval %f\n", u.fval);

    return 0;
}

使用/输出示例

PI的默认情况:

$ ./bin/floatbits
u.fval 3.141590

使用您的输入:

$ ./bin/floatbits 1 10000100 01000000001000001000000
u.fval -40.015869

重新排列Float32

的顺序

如上所述,更直接的方法是更改​​getBits的顺序,以使位域顺序为Float32,而不是在返回FRAC, EXP, SIGN之前反转位。这将使bits在内存中的顺序与fvalxval保持一致。

现在,您可以简单地在getBit中填充每个位(同时注意以适合主机的正确位顺序填充位,例如little-endian,最低有效位是范围中的最高位等)。这仅要求您认识到string[0]bit[most-significant]的每个FRAC都将映射到EXP。经过这一更改,代码将简化为:

#include <stdio.h>

/* constants for use in code (don't use magic numbers) */
enum { SIGN = 1, EXP = 8, FRAC = 23 };

typedef struct _float {
    unsigned frac:FRAC, 
             exp :EXP, 
             sign:SIGN;
} Float32;

typedef unsigned Word;  /* you need typedef for unsigned as Word */

union _bits32 {
    float    fval;      /* Bits as a float */
    Word     xval;      /* Bits as a word  */
    Float32  bits;      /* manipulate individual bits (reverse order) */
};
typedef union _bits32 Union32;

/* convert three bit-strings (already checked)
 * into the components of a struct _float
 */
Union32 getBits (char *sign, char *exp, char *frac) {

    Union32 new = { .xval = 0 };

    /* convert char *sign into a single bit in new.bits */
    new.bits.sign = *sign - '0';

    /* convert char *exp into an 8-bit value in new.bits */
    for (int i = 0; i < EXP; i++)
        new.bits.exp |= (exp[EXP - i - 1] - '0') << i;

    /* convert char *frac into a 23-bit value in new.bits */
    for (int i = 0; i < FRAC; i++)
        new.bits.frac |= (frac[FRAC - i - 1] - '0') << i;

    return new;
}

int main (int argc, char **argv) {

    union   _bits32 u = { .xval = 0 };

    /* set u (default value is PI to 3.14159) */
    u = getBits (argc > 1 ? argv[1] : "0", 
                 argc > 2 ? argv[2] : "10000000", 
                 argc > 3 ? argv[3] : "10010010000111111010000");

    /* output fval */
    printf ("u.fval %f\n", u.fval);

    return 0;
}

(使用/输出相同)

虽然位域很容易学习,但它们却很少可移植。如果您的目标是可移植代码,那么最好避免使用它们。

让我知道您是否有疑问。

答案 3 :(得分:-1)

#include <stdio.h>

int main () {

    for (char ch = 'A'; ch <= 'Z'; ++ch) {
        printf("%d\t", ch);
    }

    for (char ch = 'a'; ch <= 'z'; ++ch) {
        printf("%d\t", ch);
    }

    return 0;
}