阅读 hexdump,恐惧
Reading hexdump, fread
我有一个包含以下十六进制值的二进制文件。
使用正确的代码读取此二进制文件应显示以下内容:
第一张图中绿色高亮区域代表father, room, attraction, cake字段,输出值分别为1,1,0,1。
我必须弄清楚在下面编写的代码中,哪些数据类型用于为结构变量打印出 1,1,0,1。
我猜到 1101 来自十六进制 'd'。但是,我不确定它是如何在 4 个不同的字段中打印出来的。
我知道我的问题与结构填充或位域有关。但是,我仍然不确定我的代码和fread应该如何修改。
如果您能帮助我解决这个问题或提供示例或相关阅读材料,我们将不胜感激。
#define MAX_HAT 9
#include<stdio.h>
#include<stdlib.h>
//struct variables
struct test
{
short int land;
float experience;
char boys;
short int angle;
double industry;
int thread;
long int shoe;
float kitty;
unsigned char price;
//not sure whether this is done correctly
unsigned int father: 1;
unsigned int room: 1;
unsigned int attraction: 1;
unsigned int cake: 1;
int foot;
char hat[MAX_HAT];
char nest;
float bean;
};
int main(int argc, char **argv)
{
struct test t1;
FILE *fp;
//Input Checking Error
if (argc < 2) {
fprintf(stderr, "Usage: %s input_file\n", argv[0]);
exit(1);
}
//binary file to open for reading
fp = fopen(argv[1], "rb");
//File Checking Error
if (fp == NULL){
fprintf(stderr, "Cannot open the file %s\n", argv[1]);
exit(1);
}
//Print out struct fields
printf("land, experience, boys, angle, industry, thread, shoe, kitty, price, father, room, attraction, cake, foot, hat, nest, bean \n");
//Allocate the values into the struct
while(fread(&t1.land, sizeof(t1.land), 1, fp) == 1)
{
fread(&t1.experience, sizeof(t1.experience), 1, fp);
fread(&t1.boys, sizeof(t1.boys), 1, fp);
fread(&t1.angle, sizeof(t1.angle), 1, fp);
fread(&t1.industry, sizeof(t1.industry), 1, fp);
fread(&t1.thread, sizeof(t1.thread), 1, fp);
fread(&t1.shoe, sizeof(t1.shoe), 1, fp);
fread(&t1.kitty, sizeof(t1.kitty), 1, fp);
fread(&t1.price, sizeof(t1.price), 1, fp);
fread(&t1.father, sizeof(t1.father), 1, fp);
fread(&t1.room, sizeof(t1.room), 1, fp);
fread(&t1.attraction, sizeof(t1.attraction), 1, fp);
fread(&t1.cake, sizeof(t1.cake), 1, fp);
fread(&t1.foot, sizeof(t1.foot), 1, fp);
fread(&t1.hat, sizeof(t1.hat), 1, fp);
fread(&t1.nest, sizeof(t1.nest), 1, fp);
fread(&t1.bean, sizeof(t1.bean), 1, fp);
//Print out the outputs
printf("%d, %f, %i, %i, %f, %d, %ld, %f, %u, %, %, %, %, %x, %s, %c, %f\n", t1.land, t1.experience, t1.boys, t1.angle, t1.industry, t1.thread, t1.shoe, t1.kitty, t1.price, t1.father, t1.room, t1.attraction, t1.cake,t1.foot, t1.hat, t1.nest, t1.bean);
}
//close the file
fclose(fp);
return 0;
}
线条
fread(&t1.father, sizeof(t1.father), 1, fp);
fread(&t1.room, sizeof(t1.room), 1, fp);
fread(&t1.attraction, sizeof(t1.attraction), 1, fp);
fread(&t1.cake, sizeof(t1.cake), 1, fp);
错了。您不能对 bit-field 的成员使用 sizeof
。这样做没有意义,因为位域成员可以小于一个字节,但 sizeof
可以 return 的最小大小是一个字节。另外,fread
可以读取的最小单位是一个字节,而不是一位。
在您的问题中,您声明“突出显示区域”(2 个字节)代表 father
、room
、attraction
、cake
。但是,ISO C 只要求编译器支持大小为 int
的位域,在大多数平台上为 4 个字节。您可能想尝试使用 uint16_t
(需要 #include <stdint.h>
)而不是 unsigned int
作为位字段的基础数据类型,并希望您的编译器支持它。否则,输入数据的大小和位域的大小将不匹配,这会使事情变得更复杂。
还有一个问题是,ISO C没有规定比特在比特域中的存储顺序,即比特是从右到左还是从左到右打包。因此,如果您的输入将另一端的位打包为您的编译器,那么您将不得不对此进行补偿。
不使用位域,使用按位与运算符 &
屏蔽单个位并使用 >>
运算符移位它们可能更容易。结合使用这两个运算符可以提取单个位。
假设您有一个类型为 uint16_t
的变量 a
,您可以使用以下代码将输入文件中的两个字节读入该变量:
if ( fread( &a, sizeof a, 1, fp) != 1 )
/*handle error*/;
之后,如果你假设father
在least-significant bit中表示,那么你可以提取这些位并使用以下代码将它们分配给适当的变量:
bool father = ( a & (0x01<<0) ) >> 0;
bool room = ( a & (0x01<<1) ) >> 1;
bool attraction = ( a & (0x01<<2) ) >> 2;
bool cake = ( a & (0x01<<3) ) >> 3;
请注意,要能够使用数据类型 bool
,您必须 #include <stdbool.h>
。
有关详细信息,请参阅 bitwise operations in C。
如果您想用位域解决问题,那么我建议您更改行
unsigned int father: 1;
unsigned int room: 1;
unsigned int attraction: 1;
unsigned int cake: 1;
以下
uint16_t father: 1;
uint16_t room: 1;
uint16_t attraction: 1;
uint16_t cake: 1;
并希望您的编译器支持它(gcc 支持)并希望编译器从您输入的同一侧打包这些位。
但是,还有一个问题就是bit-field的地址是取不到的,因为它不一定是从具体的地址开始的。因此,您不能将位域的地址传递给 fread
.
因此,您必须将位域包装到它们自己的子结构中,如下所示:
struct test
{
[...]
struct
{
uint16_t father: 1;
uint16_t room: 1;
uint16_t attraction: 1;
uint16_t cake: 1;
} bitfield;
[...]
};
现在,您仍然无法获取任何位域成员的地址。但是,您可以获取包含它们的 struct
的地址,并将其传递给 fread
.
我有一个包含以下十六进制值的二进制文件。
使用正确的代码读取此二进制文件应显示以下内容:
第一张图中绿色高亮区域代表father, room, attraction, cake字段,输出值分别为1,1,0,1。
我必须弄清楚在下面编写的代码中,哪些数据类型用于为结构变量打印出 1,1,0,1。
我猜到 1101 来自十六进制 'd'。但是,我不确定它是如何在 4 个不同的字段中打印出来的。
我知道我的问题与结构填充或位域有关。但是,我仍然不确定我的代码和fread应该如何修改。
如果您能帮助我解决这个问题或提供示例或相关阅读材料,我们将不胜感激。
#define MAX_HAT 9
#include<stdio.h>
#include<stdlib.h>
//struct variables
struct test
{
short int land;
float experience;
char boys;
short int angle;
double industry;
int thread;
long int shoe;
float kitty;
unsigned char price;
//not sure whether this is done correctly
unsigned int father: 1;
unsigned int room: 1;
unsigned int attraction: 1;
unsigned int cake: 1;
int foot;
char hat[MAX_HAT];
char nest;
float bean;
};
int main(int argc, char **argv)
{
struct test t1;
FILE *fp;
//Input Checking Error
if (argc < 2) {
fprintf(stderr, "Usage: %s input_file\n", argv[0]);
exit(1);
}
//binary file to open for reading
fp = fopen(argv[1], "rb");
//File Checking Error
if (fp == NULL){
fprintf(stderr, "Cannot open the file %s\n", argv[1]);
exit(1);
}
//Print out struct fields
printf("land, experience, boys, angle, industry, thread, shoe, kitty, price, father, room, attraction, cake, foot, hat, nest, bean \n");
//Allocate the values into the struct
while(fread(&t1.land, sizeof(t1.land), 1, fp) == 1)
{
fread(&t1.experience, sizeof(t1.experience), 1, fp);
fread(&t1.boys, sizeof(t1.boys), 1, fp);
fread(&t1.angle, sizeof(t1.angle), 1, fp);
fread(&t1.industry, sizeof(t1.industry), 1, fp);
fread(&t1.thread, sizeof(t1.thread), 1, fp);
fread(&t1.shoe, sizeof(t1.shoe), 1, fp);
fread(&t1.kitty, sizeof(t1.kitty), 1, fp);
fread(&t1.price, sizeof(t1.price), 1, fp);
fread(&t1.father, sizeof(t1.father), 1, fp);
fread(&t1.room, sizeof(t1.room), 1, fp);
fread(&t1.attraction, sizeof(t1.attraction), 1, fp);
fread(&t1.cake, sizeof(t1.cake), 1, fp);
fread(&t1.foot, sizeof(t1.foot), 1, fp);
fread(&t1.hat, sizeof(t1.hat), 1, fp);
fread(&t1.nest, sizeof(t1.nest), 1, fp);
fread(&t1.bean, sizeof(t1.bean), 1, fp);
//Print out the outputs
printf("%d, %f, %i, %i, %f, %d, %ld, %f, %u, %, %, %, %, %x, %s, %c, %f\n", t1.land, t1.experience, t1.boys, t1.angle, t1.industry, t1.thread, t1.shoe, t1.kitty, t1.price, t1.father, t1.room, t1.attraction, t1.cake,t1.foot, t1.hat, t1.nest, t1.bean);
}
//close the file
fclose(fp);
return 0;
}
线条
fread(&t1.father, sizeof(t1.father), 1, fp);
fread(&t1.room, sizeof(t1.room), 1, fp);
fread(&t1.attraction, sizeof(t1.attraction), 1, fp);
fread(&t1.cake, sizeof(t1.cake), 1, fp);
错了。您不能对 bit-field 的成员使用 sizeof
。这样做没有意义,因为位域成员可以小于一个字节,但 sizeof
可以 return 的最小大小是一个字节。另外,fread
可以读取的最小单位是一个字节,而不是一位。
在您的问题中,您声明“突出显示区域”(2 个字节)代表 father
、room
、attraction
、cake
。但是,ISO C 只要求编译器支持大小为 int
的位域,在大多数平台上为 4 个字节。您可能想尝试使用 uint16_t
(需要 #include <stdint.h>
)而不是 unsigned int
作为位字段的基础数据类型,并希望您的编译器支持它。否则,输入数据的大小和位域的大小将不匹配,这会使事情变得更复杂。
还有一个问题是,ISO C没有规定比特在比特域中的存储顺序,即比特是从右到左还是从左到右打包。因此,如果您的输入将另一端的位打包为您的编译器,那么您将不得不对此进行补偿。
不使用位域,使用按位与运算符 &
屏蔽单个位并使用 >>
运算符移位它们可能更容易。结合使用这两个运算符可以提取单个位。
假设您有一个类型为 uint16_t
的变量 a
,您可以使用以下代码将输入文件中的两个字节读入该变量:
if ( fread( &a, sizeof a, 1, fp) != 1 )
/*handle error*/;
之后,如果你假设father
在least-significant bit中表示,那么你可以提取这些位并使用以下代码将它们分配给适当的变量:
bool father = ( a & (0x01<<0) ) >> 0;
bool room = ( a & (0x01<<1) ) >> 1;
bool attraction = ( a & (0x01<<2) ) >> 2;
bool cake = ( a & (0x01<<3) ) >> 3;
请注意,要能够使用数据类型 bool
,您必须 #include <stdbool.h>
。
有关详细信息,请参阅 bitwise operations in C。
如果您想用位域解决问题,那么我建议您更改行
unsigned int father: 1;
unsigned int room: 1;
unsigned int attraction: 1;
unsigned int cake: 1;
以下
uint16_t father: 1;
uint16_t room: 1;
uint16_t attraction: 1;
uint16_t cake: 1;
并希望您的编译器支持它(gcc 支持)并希望编译器从您输入的同一侧打包这些位。
但是,还有一个问题就是bit-field的地址是取不到的,因为它不一定是从具体的地址开始的。因此,您不能将位域的地址传递给 fread
.
因此,您必须将位域包装到它们自己的子结构中,如下所示:
struct test
{
[...]
struct
{
uint16_t father: 1;
uint16_t room: 1;
uint16_t attraction: 1;
uint16_t cake: 1;
} bitfield;
[...]
};
现在,您仍然无法获取任何位域成员的地址。但是,您可以获取包含它们的 struct
的地址,并将其传递给 fread
.