*(int*)&data[18]在这段代码中实际上做了什么?



我遇到了这种语法来读取 BMP 文件C++

#include <fstream>
int main() {
std::ifstream in('filename.bmp', std::ifstream::binary);
in.seekg(0, in.end);
size = in.tellg();
in.seekg(0);
unsigned char * data = new unsigned char[size];
in.read((unsigned char *)data, size);
int width = *(int*)&data[18];
// omitted remainder for minimal example
}

我不明白这句话是什么

int width = *(int*)&data[18];

实际上正在做。为什么从unsigned char *intint width = (int)data[18];的简单演员阵容不起作用?

注意

如注释中所述@user4581301,这取决于实现,并且在许多情况下会失败。正如@NathanOliver-恢复莫妮卡和@ChrisMM指出的那样,这是未定义的行为,结果无法保证。

根据位图标头格式,位图的宽度(以像素为单位(存储为从字节偏移量 18 开始的有符号 32 位整数。语法

int width = *(int*)&data[18];

读取字节 19 到 22(包括 32 位((假设 32 位int(并将结果解释为整数。

如何?

  • &data[18]获取索引 18 处unsigned char的地址
  • (int*)将地址从unsigned char*转换为int*,以避免在 64 位架构上损失精度
  • *(int*)取消引用地址以获取引用的int

所以基本上,它采用data[18]的地址并读取该地址的字节,就好像它们是整数一样。

为什么简单的"int"投射不起作用?

sizeof(data[18])1,因为unsigned char是一个字节(0-255(,但如果系统是32位sizeof(&data[18])4,如果它是64位,则8,它可以更大(对于16位系统甚至更小(,但除了16位系统之外,它至少应该为4字节。显然,在这种情况下不需要读取超过4个字节,并且强制转换为(int*)并随后取消引用int会产生4个字节,实际上是偏移量 18 和 21 之间的 4 个字节(包括 18 和 21(。从unsigned charint的简单转换也将产生 4 个字节,但只有来自data的一个字节的信息。以下示例对此进行了说明:

#include <iostream>
#include <bitset>
int main() {
// Populate 18-21 with a recognizable pattern for demonstration
std::bitset<8> _bits(std::string("10011010"));
unsigned long bits = _bits.to_ulong();
for (int ii = 18; ii < 22; ii ++) {
data[ii] = static_cast<unsigned char>(bits);
}
std::cout << "data[18]                    -> 1 byte  " 
<< std::bitset<32>(data[18]) << std::endl;
std::cout << "*(unsigned short*)&data[18] -> 2 bytes " 
<< std::bitset<32>(*(unsigned short*)&data[18]) << std::endl;
std::cout << "*(int*)&data[18]            -> 4 bytes " 
<< std::bitset<32>(*(int*)&data[18]) << std::endl;
}
data[18]                    -> 1 byte  00000000000000000000000010011010
*(unsigned short*)&data[18] -> 2 bytes 00000000000000001001101010011010
*(int*)&data[18]            -> 4 bytes 10011010100110101001101010011010

相关内容

  • 没有找到相关文章

最新更新