1.关于打开文件的问题
现在有一个问题,我想用二进制形式打开一个exe可执行文件,并且输出其中的二进制数据,应该怎么办。不讲太多,直接上代码。
#include <stdio.h>
#include <ctype.h>
int main()
{
FILE *fp;
char ch[50];
int ch1;
scanf("%s",ch);
fp=fopen(ch,"rb");
if(fp==NULL)
printf("ERROR");
else
{
ch1=fgetc(fp);
while(ch1!=EOF)
{
//if(isalnum(ch1)!=0)
printf("%x",ch1);
//else
//printf(" 00");
ch1=fgetc(fp);
}
}
return 0;
}
对该程序进行一些补充,这个程序关键的问题在于,fgetc函数的返回值为一个int类型,如果定义的ch1是char类型的,那么输出时会将fgetc返回的int类型看成对应字符的ascii码,虽然会转化为对应的字符,但是会有很多的缺省,因为在exe文件中(这里特指dos中的exe文件,因为对windows中的exe文件不太了解),开始的若干个字节的文件描述后面通常会跟着一堆的0,这些会被翻译为空字符,不会被显示出来,所以我们将ch1变量写作整型。返回的值正确。
2.关于C中的signed与unsigned的区别
先给个例子,
#include <stdio.h>
void f(unsigned char v)
{
char c = v;
unsigned char uc = v;
unsigned int a = c, b = uc;
int i = c, j = uc;
printf("----------------\n");
printf("%%c: %c, %c\n", c, uc);
printf("%%X: %X, %X\n", c, uc);
printf("%%u: %u, %u\n", a, b);
printf("%%d: %d, %d\n", i, j);
}
int main(int argc, char *argv[])
{
f(0x80);
f(0x7F);
return 0;
}
对该程序进行一个简单的补充解释。首先是在内存中,signed与unsigned类型没有本质的区别,都是一个字节,唯一的区别是signed最高位被看成符号位,所以signed的取值范围为-128~127(关于为什么取值为-128,这个是和补码有关的一个人为的规定,详细了解可以去百度查),unsigned不存在符号位的情况,所以取值范围为0到255。主要是符号位,但是在普通的赋值,读写文件和网络字节流都没什么区别,反正就是一个字节,不管最高位是什么,最终的读取结果都一样,只是你怎么理解最高位而已,在屏幕上面的显示可能不一样。
但是我们却发现在表示byte时,都用unsigned char,这是为什么呢?
首先关于byte,这个玩意通常意义上来讲你单单看他,他不存在什么符号。(符号这个玩意是编译器所认为的,就是进行人为规定的)。但是在赋值的时候会有问题。更重要的是如果将byte的值赋给int,long等数据类型时,系统会做一些额外的工作。(事实上来说byte类型在c语言中是存在的,但是我们不推荐用byte类型,一般来说都用unsigned char,就像上面程序所示的那样,下文中的byte类型可以看成unsigned char)如果我们将byte类型赋值给char类型,那么编译器会对最高位进行扩展,如果byte为0x80,那么赋值后,char类型为0xFFFFFF80,这个值实际上是一个补码,计算机中为了方便计算都会以补码保存数据,如果我们把它转换成对应的原码,它的值为0x80000080
也就是1000 0000 0000 0000 0000 0000 1000 0000,这个值为-0x80,如果我们不那么严谨的来看的话,char类型与对应的byte类型的值只差一个符号,值是相同的。这个例子意味着在将byte类型的值赋值给char类型时,系统对char类型的最高位进行了填充,如果byte类型的值的最高位为0,那么系统在char类型中填充时,高位全部为0,如果byte类型的值的最高位为1,那么系统在char类型中填充时,会将最高位填充为1,其余为0,进行求补操作后就会变成类似FFFF这样的高位数据。如果将被同一个byte类型赋值的char与unsigned char同时用%c进行输出的话,他们的值是相同的,这个原因可能是编译器在通过%c输出一个变量是只看前一个字节的信息,如果只看前一个字节的信息,char与unsigned char 类型的值是相同的,所以翻译为同一个字符。(按道理来说如果你给一个例如0x80的值给char与unsigned char他们都不会被翻译为任何的字符,但是在我的vc中他们被翻译为了一个罗马字符,很有可能ascii码有额外的扩展,这个就不深究了。)同样的,如果把一个值为0x80的byte类型变量先赋值给char与unsigned char,之后用char与unsigned char分别为int类型的变量赋值,最后用%d输出,发现被char类型赋值的int输出为-128,被unsigned char类型赋值的int输出128,对照着上面的解释,出现如此结果的原因应该明了了。