从字节数组 char[] 中获取 int 值

4

我有一个文件,我将它读入到一个字符数组中。

现在,如果我知道文件在位置0x8处以little endian格式存储了一个32位整数,那么我该如何从字符数组中检索它呢?

FILE * file = fopen("file");
char buffer[size];
fread(buffer,1,size,file);
int = buffer[0x8]; // What should I do here?
// I imagine it involves some strange pointer
// arithmetic but I can't see what I should do,
// casting to int just takes the first byte,
// casting to (int *) doesn't compile
4个回答

4

“简单”方法假设该数组包含与您的机器相同字节序的字节,并且没有任何特殊对齐要求,操作如下:

int x = *(int *)&buffer[8];

如果存在字节序差异,您需要处理它。如果存在对齐问题(甚至可能存在对齐问题),您应该逐个提取字节:

int x = buffer[8] + (buffer[9] << 8) + (buffer[10] <<  16) + (buffer[11] << 24);

如果字节顺序相反,也可能是另一个方向。


1
+1。我只想补充一点,*((int*)(buffer + 8))是相同的。很可能你的机器是little-endian架构——英特尔或 AMD... - LihO

3
您需要这样转换它:

像这样:

int foo = *((int *) &buffer[0x8]);

首先将该点转换为int指针,然后对其进行解引用以得到int本身。

[注意不同机器类型之间的字节顺序;有些是高字节优先,有些是低字节优先]

为了确保示例被充分理解,以下是一些展示结果的代码:

#include <stdio.h>

main() {
    char buffer[14] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13 };
    int foo = *((int *) &buffer[0x8]);
    int bar = (int) buffer[0x8];

    printf("raw: %d\n", buffer[8]);
    printf("foo: %d\n", foo);
    printf("bar: %d\n", bar);
}

运行后的结果如下:

raw: 8
foo: 185207048
bar: 8

1
@cnicutar 你确定吗?buffer[0x8]是对(buffer + offset)进行解引用。它返回一个值,而不是指针。将该值强制转换为int指针会指向谁知道哪里的内存地址。 - calebds
@cnicutar,不是这样的。实际上,这是必需的。如果您使用此方法,请注意您的机器可能具有的任何对齐要求。 - Carl Norum
buffer[0x8] 将返回缓冲区中第 8 个位置的单个字节。&buffer[0x8] 将返回缓冲区中第 8 个字节的内存位置,这就是需要进行转换的内容。您不想对缓冲区 8 号位置上的数字进行取消引用操作。 - Wes Hardaker
@Carl Norum,是的,我错了 :-) 当然需要(由于某种原因,我读成了“buffer”,而不是“buffer[0x8]”)。 - cnicutar

1

将4字节值的字节序进行转换是通过改变该值的两个字(16位)来完成的,因此如果数据采用大端编码,则效率较低但易读的方法是:

int val = 0x00000000;
char* ptr = reinterpret_cast<char*>(&val);
*ptr = buffer[0x0a];
ptr++;
*ptr = buffer[0x0b];
ptr++;
*ptr = buffer[0x08];
ptr++;
*ptr = buffer[0x09];
ptr++;

但是还有许多其他方法可以实现,例如结构体、memcpy等,这取决于您的目标(性能、可读性等)

最好的问候, Alex


0
int *list = (int*)buffer;
int n = fread(buffer, 1, size, file);
for (int i=0; i< n/sizeof(int); i++)
  printf("%d\n", list[i]);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接