我读过有关[ostream] << hex << 0x[hex value]
的内容,但我对此有一些疑问
(1)我使用output
将我的文件流output.open("BWhite.bmp",ios::binary);
定义为十六进制输出文件流,因为我这样做了,这会使hex
参数成为output<<
操作多余?
(2) 如果我有一个整数值,我想存储在文件中,我使用了这个:
int i = 0;
output << i;
我会以小端或大端存储吗?根据执行或编译程序的计算机,endi-ness是否会发生变化?
此值的大小是否取决于它运行的计算机?我需要使用hex参数吗?
(3)有没有办法将原始十六进制数字输出到文件?如果我希望文件具有十六进制数字43,我应该使用什么?
output << 0x43
和output << hex << 0x43
都输出ASCII 4,然后输出ASCII 3。
输出这些十六进制数字的目的是制作.bmp文件的标题。
答案 0 :(得分:7)
格式化的输出运算符<<
仅用于:格式化输出。这是字符串。
因此,std::hex
流操纵器告诉流将数字输出为格式为十六进制的字符串。
如果要输出原始二进制数据,请使用未格式化的输出函数 ,例如basic_ostream::put
和basic_ostream::write
。
你可以像这样输出一个int:
int n = 42;
output.write(&n, sizeof(int));
此输出的字节顺序取决于体系结构。如果您希望获得更多控制权,我建议如下:
int32_t n = 42;
char data[4];
data[0] = static_cast<char>(n & 0xFF);
data[1] = static_cast<char>((n >> 8) & 0xFF);
data[2] = static_cast<char>((n >> 16) & 0xFF);
data[3] = static_cast<char>((n >> 24) & 0xFF);
output.write(data, 4);
此示例将输出32位整数作为little-endian,而不管平台的字节顺序如何。但是,如果char
已签名,请小心转换回去。
答案 1 :(得分:7)
你说
“有没有办法将原始十六进制数字输出到文件?如果我希望文件具有十六进制数字43,我应该使用什么?”
“原始十六进制数字”取决于您对一组位的解释。请考虑以下事项:
Binary : 0 1 0 0 1 0 1 0
Hex : 4 A
Octal : 1 1 2
Decimal : 7 4
ASCII : J
以上所有代表相同的数字量,但我们对它的解释不同。
因此,您只需将数据存储为二进制格式,即由数字表示的精确位模式。
<强> EDIT1 强>
当您以文本模式打开文件并在其中写入数字时,请说当您编写74
时(如上例所示),它将存储为两个ASCII字符'7'
和{{1 }。为避免这种情况,请以二进制模式'4'
打开文件,并使用ios::binary
进行编写。查看http://courses.cs.vt.edu/~cs2604/fall00/binio.html#write
答案 2 :(得分:3)
输出这些十六进制数字的目的是制作.bmp文件的标题。
您似乎对文件的工作方式存在很大的误解。
流操作符<<
生成文本(人类可读输出)。 .bmp文件格式是一种二进制格式,不是人类可读的(它会不会很好,我不会在没有工具的情况下阅读它。)
您真正想要做的是生成二进制输出并将其放在文件中:
char x = 0x43;
output.write(&x, sizeof(x));
这会将十六进制值0x43的一个字节数据写入输出流。这是您想要的二进制表示。
我会以小端或大端存储吗?根据执行或编译程序的计算机,endi-ness是否会发生变化?
既不;你又在输出文字(不是二进制数据)。
int i = 0;
output.write(reinterpret_cast<char*>(&i), sizeof(i)); // Writes the binary representation of i
在这里,您需要担心整数值的endianess(和大小),这将根据您运行应用程序的硬件而有所不同。对于值0,没有太多关于endianess的担心,但你应该担心整数的大小。
我会在代码中添加一些断言来验证代码的架构是否正常。然后让人们担心他们的架构是否符合要求:
int test = 0x12345678;
assert((sizeof(test) * CHAR_BITS == 32) && "BMP uses 32 byte ints");
assert((((char*)&test)[0] == 0x78) && "BMP uses little endian");
有一系列功能可以帮助您获得结束和大小。
http://www.gnu.org/s/hello/manual/libc/Byte-Order.html
功能:uint32_t htonl(uint32_t hostlong)
此函数将uint32_t整数hostlong从主机字节顺序转换为网络字节顺序。
// Writing to a file
uint32_t hostValue = 0x12345678;
uint32_t network = htonl(hostValue);
output.write(&network, sizeof(network));
// Reading from a file
uint32_t network;
output.read(&network, sizeof(network);
uint32_t hostValue = ntohl(network); // convert back to platform specific value.
// Unfortunately the BMP was written with intel in-mind
// and thus all integers are in liitle-endian.
// network bye order (as used by htonl() and family) is big endian.
// So this may not be much us to you.
最后一件事。当您以二进制格式output.open("BWhite.bmp",ios::binary)
打开文件时,除了处理end of line sequence
的方式之外,它不会产生任何影响。当文件是二进制格式时,输出不会被修改(您在流中放入的内容是写入文件的内容)。如果将流保留为文本模式,则'\ n'字符将转换为行结束序列(特定于操作系统的字符串,用于定义行尾)。由于您正在编写二进制文件,因此您绝对不希望对所写的字符产生任何干扰,因此二进制文件的格式正确。但它不会影响您在流上执行的任何其他操作。