我正在编写这样的程序,将一些字节写入文件.
#include <fstream>
int main()
{
char buffer[4] = {0, 0, 255, 255};
std::ofstream f("foo.txt", std::ios_base::binary);
f.write(buffer, sizeof buffer);
f.close();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这很好,并在我的系统上给我预期的结果.
$ g++ -std=c++11 -pedantic -Wall -Wextra signedness.cc
$ ./a.out
$ cat foo.txt
$ od -t x1 foo.txt
0000000 00 00 ff ff
0000004
Run Code Online (Sandbox Code Playgroud)
等效的C代码是:
#include <stdio.h>
int main()
{
char buffer[4] = {0, 0, 255, 255};
FILE *f = fopen("bar.txt", "wb");
fwrite(buffer, sizeof *buffer, sizeof buffer, f);
fclose(f);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该程序也可以正常工作,并在我的系统上提供预期的输出.
我想知道上述将字节写入文件的方法是否合适.
C++ n3242.pdf的第4.7节(积分转换)在第3点中提到:
如果目标类型已签名,则如果可以在目标类型(和位字段宽度)中表示该值,则该值不会更改; 否则,该值是实现定义的.
C n1256.pdf的第6.3.1.3节(有符号和无符号整数)在第3点中提到:
否则,新类型将被签名,并且值无法在其中表示; 结果是实现定义的,或者引发实现定义的信号.
从这些提取中,当我将255指定为最后两个字节时,似乎我的程序调用实现定义的行为,char buffer[4]因为255不能在char类型中表示.如果我对此是正确的,那么将这四个字节写入文件的正确方法是什么?更改的类型buffer从char到unsigned char似乎并不在C++帮助,因为ofstream的的write()功能仍预期的第一个参数类型const char*.
请记住,这ofstream只是一个typedef std::basic_ofstream<char>.
当你不想把事情当作对待时char,只需使用std::basic_ofstream<unsigned char>或std::basic_ofstream<uint8_t>.
但最终,iostream是为格式化I/O而制作的.API对于二进制I/O来说非常糟糕(因为它不需要void*),而且速度也非常慢.此外,每个字符都由"facet"转换,这使得很难保证磁盘上输入字节和字节之间的1:1对应关系. basic_filebuf有点好,但不多.使用fopen和fwrite仍然是一种非常有效的方法,即使在C++中也是如此.