我正在涉足Game Boy保存状态黑客,我目前正在从c二进制文件中读取我的头。我知道char
是一个字节,所以我正在使用以下代码读取字符
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
int main () {
FILE *fp = NULL;
char buffer[100];
int filesize;
fp = fopen("save file.srm", "r+"); //open
if(fp == NULL) printf("File loading error number %in", errno);
fseek(fp, 0L, SEEK_END); //seek to end to get file size
filesize = ftell(fp);
printf("Filesize is %i bytesn",filesize);
fseek(fp, 0, SEEK_SET); //set read point at start of file
fread(buffer, sizeof buffer, 1, fp);//read into buffer
for(int i=70;i<80;i++) printf("%xn", buffer[i]); //display
fclose(fp);
return(0);
}
我得到的输出是
Filesize is 32768 bytes
ffffff89
66
ffffff85
2
2
ffffff8b
44
ffffff83
c
0
我试图以字节加载,所以我希望输出的每一行都具有最大值0xff。有人能解释一下为什么我得到ffffff8b吗?
if(fp == NULL) printf("File loading error number %in", errno);
当您检测到错误时,不要只是打印一条消息。要么退出程序,要么做一些事情来纠正错误。
char buffer[10];
使用unsigned char
处理原始数据。char
可能被签名,这可能会导致不希望的效果。
fread(buffer, strlen(buffer)+1, 1, fp);
此时buffer
还没有初始化,所以strlen(buffer)
的行为还没有被C标准定义。在任何情况下,您都不希望使用buffer
中当前字符串的长度作为fread
的大小。你想知道数组的大小。所以使用sizeof buffer
(不使用+1
)。
for(int i=0;i<10;i++)
不要迭代到10。迭代fread
放入缓冲区的字节数。fread
返回size_t
值,即读取的项数。如果您将其用作size_t n = fread(buffer, 1, sizeof buffer, fp);
,则项目的数量(在n
中)将是读取的字节数,因为第二个参数为1
表示要读取的每个项目是一个字节。
printf("%xn", buffer[i]);
打印unsigned char
,使用%hhx
。因为你的buffer
对char
元素有符号,所以有些元素是负的。当在printf
中使用时,它们被提升为负int
值。然后,由于%x
,printf
试图将它们打印为unsigned int
值。在2的补码形式中,所有来自负值的额外位都显示出来。
非常简单:char
可以默认为signed
或unsigned
:这取决于编译器。在您的情况下,它似乎是signed
.
当你将buffer[i]
的char
传递给printf()
时,它被提升为int
,如果原来的char
值已经设置了它的顶位,那么它的符号扩展。因此,在0x80-0xff范围内的任何内容都会获得大量的f
前缀值。
如果将buffer
声明为unsigned char
,则不应出现此问题。但是,您应该结合printf()
格式使用"%hhx"
而不是"%x"
,因为hh
长度修饰符强制printf()
屏蔽输入值,以便仅使用适用于unsigned char
的那些位(假设您正在使用x
说明符)。