代码=>
#include<stdio.h>
typedef struct {
unsigned short c2;
unsigned long c4;
} TAKECH;
int main() {
TAKECH tch;
FILE *fp_in;
fp_in = fopen("in.txt","rb");
fread(&tch,6,1,fp_in);
printf("First two bytes: %x\n",tch.c2);
printf("Next four bytes: %x\n",tch.c4);
fclose(fp_in);
return 0;
}
输出=&gt;
First two bytes: 6261
Next four bytes: bfd56665
in.txt =&gt;
abcdef
Hexeditor(vim编辑器:%!xxd)显示此=&gt;
0000000: 6162 6364 6566 0a abcdef.
需要解释输出:
First two bytes: 6261
&lt; - 为什么它的顺序相反?
First two bytes: 6162
&lt; - 不应该这样吗?
为什么我不能在输出中获得6364
?如何使用printf("Next four bytes: %x\n",tch.c4);
获得接下来的四个字节(6364 6566)为什么我得到Next four bytes: bfd56665
bfd5
来自哪里?
任何答案都将受到高度赞赏。
提前致谢。
答案 0 :(得分:3)
您应该为fread
使用缓冲区(请参阅http://en.cppreference.com/w/c/io/fread上的示例),而不是struct
。
由于padding,您只能从文件中获得两个“正确”字节(65
和66
)。 c4
的其他字节未初始化。
对于订单“问题”,您可以查看:Why does fread mess with my byte order?
这取决于机器/编译器,因此实际结果可能会有所不同。
typedef struct
{
uint16_t c2;
uint32_t c4;
} TAKECH;
sizeof(TAKECH)
为8
(不是6
= sizeof(c2) + sizeof(c4)
):添加了填充以满足对齐约束(数据结构对齐会影响程序的性能和正确性)。< / p>
typedef struct
{
uint16_t c2; /* 2 bytes */
/* 2 padding bytes */
uint32_t c4; /* 4 bytes */
} TAKECH;
(另见Why isn't sizeof for a struct equal to the sum of sizeof of each member?)。
答案 1 :(得分:2)
答案 2 :(得分:1)
您可以建议您在分配之前清除您的tch结构,因为它充满了垃圾。
是的,我真的不明白为什么我在这里投票,但你知道我会添加一些代码来证明我的观点:
mmcmbp:scratch abe$ cat main.c
#include <stdio.h>
#include <string.h>
typedef struct {
unsigned short c2;
unsigned long c4;
} TAKECH;
int main() {
TAKECH tch;
FILE *fp_in;
memset(&tch, 0, sizeof(TAKECH));
printf("Before\n");
printf("First two bytes: %hu\n",tch.c2);
printf("Next four bytes: %lu\n",tch.c4);
fp_in = fopen("in.txt","rb");
fread(&tch,6,1,fp_in);
printf("After:\n");
printf("First two bytes: %hu\n",tch.c2);
printf("Next four bytes: %lu\n",tch.c4);
fclose(fp_in);
return 0;
}
mmcmbp:scratch abe$ clang main.c -o main
mmcmbp:scratch abe$ ./main
Before
First two bytes: 0
Next four bytes: 0
After:
First two bytes: 25185
Next four bytes: 0
根据字节的顺序,是的,字节顺序可以决定它,并且是其他人所说的。
答案 3 :(得分:1)
大多数编译器都支持“pack”编译指示,它允许您指定结构成员在内存中的布局方式。此示例显示使用size-1成员对齐的打包将使您的struct与文件的布局匹配。但是,当你不需要它时,你不想使用这种打包,因为它会降低性能,并且可能因为内存访问错位而导致其他问题。
#include <iostream>
#include <cstring>
typedef struct {
unsigned short c2;
unsigned long c4;
} TAKECH;
#pragma pack(push,1)
typedef struct {
unsigned short c2;
unsigned long c4;
} TAKECH_packed_1;
#pragma pack(pop)
const unsigned char data[] = "\x61\x62\x63\x64\x65\x66\x0a\xff\xfe\xfd\xfc";
int main() {
TAKECH original;
std::memcpy(&original, &data, sizeof(original));
std::cout << std::hex;
std::cout << "Default packing:\n";
std::cout << " c2: " << original.c2 << '\n';
std::cout << " c4: " << original.c4 << '\n';
TAKECH_packed_1 packed;
std::memcpy(&packed, &data, sizeof(packed));
std::cout << "\nByte packing:\n";
std::cout << " c2: " << packed.c2 << '\n';
std::cout << " c4: " << packed.c4 << '\n';
}
此输出
Default packing:
c2: 6261
c4: ff0a6665
Byte packing:
c2: 6261
c4: 66656463
答案 4 :(得分:0)
如果TAKECH
布局如下,那么您的代码就可以使用:
Low address High address
| c2 | c4 |
| Byte 1 | Byte 0 | Byte 3 | Byte 2 | Byte 1 | Byte 0 |
但实际上它的布局如下:
Low address High address
| c2 | Padding | c4 |
| Byte 0 | Byte 1 | | | Byte 0 | Byte 1 | Byte 2 | Byte 3 |
tch: 61 62 63 64 65 66 junk(d5) junk(bf)
第一个问题,即排序,是由于您的计算机是 little-endian - 多字节整数的最低有效字节存储在较低的地址。
第二个问题是由于您假设sizeof(TAKECH)
为6
不是;已填充以使c4
的地址为sizeof(unsigned long)
的倍数
这导致tch
的一部分(&#34;顶部&#34; tch.c4
的两个字节)在您只读取六个字节时未初始化。
可靠且便携的解决方案是分别阅读每个成员
fread(&tch.c2, sizeof(tch.c2), 1, fp_in);
fread(&tch.c4, sizeof(tch.c4), 1, fp_in);
然后调整字节顺序。
摘要:
sizeof
而不是依赖于假设。答案 5 :(得分:0)