程序的工作方式
./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;
}
答案 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.bits
和new.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;
之前new
中getBits
中return
的位,例如
/* 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_BIT
从limits.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
在内存中的顺序与fval
和xval
保持一致。
现在,您可以简单地在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;
}