*(int*)&data[18] 在这段代码中实际做了什么?
What is *(int*)&data[18] actually doing in this code?
我遇到了用 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 *
到 int
、int width = (int)data[18];
的简单转换不起作用?
Note
As @user4581301 indicated in the comments, this depends on the implementation and will fail in many instances. And as @NathanOliver- Reinstate Monica and @ChrisMM pointed out this is Undefined Behavior and the result is not guaranteed.
根据 bitmap header format,以像素为单位的位图宽度存储为从字节偏移量 18 开始的有符号 32 位整数。语法
int width = *(int*)&data[18];
读取字节 19 到 22,包括在内(假设 32 位 int
)并将结果解释为整数。
怎么样?
&data[18]
在索引 18 获取 unsigned char
的地址
(int*)
将地址从 unsigned char*
转换为 int*
以避免 loss of precision on 64 bit architectures
*(int*)
取消引用地址以获得引用的 int
值
所以基本上,它获取 data[18]
的地址并读取该地址处的字节,就好像它们是整数一样。
为什么简单转换为 `int` 不起作用?
sizeof(data[18])
是1
,因为unsigned char
是一个字节(0
-255
)但是sizeof(&data[18])
是4
如果系统是 32 位,8
如果是 64 位,这可以是 larger (or even smaller for 16-bit systems) 但除了 16 位系统外,它应该至少是 4
字节。显然在这种情况下不希望读取超过 4
个字节,并且强制转换为 (int*)
和随后对 int
的取消引用会产生 4
个字节,实际上偏移量之间的 4 个字节18 和 21,包括在内。从 unsigned char
到 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
我遇到了用 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 *
到 int
、int width = (int)data[18];
的简单转换不起作用?
Note
As @user4581301 indicated in the comments, this depends on the implementation and will fail in many instances. And as @NathanOliver- Reinstate Monica and @ChrisMM pointed out this is Undefined Behavior and the result is not guaranteed.
根据 bitmap header format,以像素为单位的位图宽度存储为从字节偏移量 18 开始的有符号 32 位整数。语法
int width = *(int*)&data[18];
读取字节 19 到 22,包括在内(假设 32 位 int
)并将结果解释为整数。
怎么样?
&data[18]
在索引 18 获取 (int*)
将地址从unsigned char*
转换为int*
以避免 loss of precision on 64 bit architectures*(int*)
取消引用地址以获得引用的int
值
unsigned char
的地址
所以基本上,它获取 data[18]
的地址并读取该地址处的字节,就好像它们是整数一样。
为什么简单转换为 `int` 不起作用?
sizeof(data[18])
是1
,因为unsigned char
是一个字节(0
-255
)但是sizeof(&data[18])
是4
如果系统是 32 位,8
如果是 64 位,这可以是 larger (or even smaller for 16-bit systems) 但除了 16 位系统外,它应该至少是 4
字节。显然在这种情况下不希望读取超过 4
个字节,并且强制转换为 (int*)
和随后对 int
的取消引用会产生 4
个字节,实际上偏移量之间的 4 个字节18 和 21,包括在内。从 unsigned char
到 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