c++ - *(int*)&data[18] 在这段代码中实际上在做什么?
问题描述
我遇到了这种用 C++ 读取 BMP 文件的语法
#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 *
to int
, int width = (int)data[18];
, 的简单转换不起作用?
解决方案
笔记
正如@user4581301在评论中指出的那样,这取决于实现,并且在许多情况下都会失败。正如@NathanOliver- Reinstate Monica和@ChrisMM指出的那样,这是未定义的行为,结果无法保证。
根据位图头格式,位图的宽度(以像素为单位)存储为一个有符号的 32 位整数,从字节偏移量 18 开始。语法
int width = *(int*)&data[18];
读取 19 到 22 字节(包括 32 位int
)并将结果解释为整数。
如何?
&data[18]
获取unsigned char
索引 18 处的地址(int*)
将地址转换为unsigned char*
toint*
以避免64 位架构上的精度损失*(int*)
取消引用地址以获取引用的int
值
所以基本上,它获取地址data[18]
并读取该地址的字节,就好像它们是整数一样。
为什么简单的转换为 `int` 不起作用?
sizeof(data[18])
是1
,因为unsigned char
是一个字节(0
- 255
),但是sizeof(&data[18])
如果4
系统是 32 位,8
如果是 64 位,则它可以更大(对于 16 位系统甚至更小),但 16 位系统除外应该是最小4
字节。4
显然,在这种情况下不希望读取超过字节,并且强制转换(int*)
和随后的取消引用int
产生4
字节,实际上是偏移量 18 和 21 之间的 4 个字节,包括在内。一个简单的 from unsigned char
to 转换int
也将产生 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
推荐阅读
- sql - SQL Server 锁定的 UPDATE 优化
- html - 将 Div 调整为与背景图像相同的尺寸
- node.js - nodejs:无法从主函数中的回调函数读取响应
- angular - 如何在 Angular 应用程序的主项目中使用 Puppeteer?
- amazon-web-services - Lex:服务器在处理 lambda 时遇到错误
- google-sheets - 如何通过几个步骤仅在 Google 表格中复制公式(没有值或格式)?
- java - Android Java将mp3文件名字符串传递给片段内的媒体播放器
- influxdb - InfluxDB Flux 连接系列
- json - 导出包含 JSON 列且没有双重转义的 SQLite 表
- r - 对正或负“条纹”的值求和