4

我正在编写这样的程序来将一些字节写入文件。

#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;
}

这工作正常,并在我的系统上给了我预期的结果。

$ 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

等效的 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;
}

该程序也可以正常工作,并在我的系统上提供预期的输出。

我想知道上述将字节写入文件的方式是否可以。

C++ n3242.pdf的第 4.7 节(积分转换)在第 3 点中提到:

如果目标类型是有符号的,则如果它可以在目标类型(和位域宽度)中表示,则该值不变;否则,该值是实现定义的。

C n1256.pdf的第 6.3.1.3 节(有符号和无符号整数)在第 3 点中提到:

否则,新类型是有符号的,值不能在其中表示;结果是实现定义的,或者引发了实现定义的信号。

从这些摘录中,当我将 255 分配为最后两个字节时,我的程序似乎调用了实现定义的行为,char buffer[4]因为 255 不能用char类型表示。如果我对此是正确的,那么将这四个字节写入文件的正确方法是什么?更改bufferfrom的类型在 C++ 中char似乎unsigned char没有帮助,因为 ofstream 的write()函数仍然需要第一个参数 to 的 type const char*

4

3 回答 3

5

请记住,这ofstream只是std::basic_ofstream<char>.

当您不希望将事物视为 时char,只需使用std::basic_ofstream<unsigned char>or std::basic_ofstream<uint8_t>

但最终,iostream 是为格式化的 I/O 制作的。该 API 对于二进制 I/O 来说是可怕的(因为它不需要void*),而且速度也非常慢。此外,每个字符都由一个“平面”转换,因此很难保证输入字节和磁盘上的字节之间的 1:1 对应关系。 basic_filebuf稍微好一点,但不多。即使在 C++ 中,使用fopenandfwrite仍然是一种完全有效的方法。

于 2012-09-17T22:25:12.530 回答
0

诚然,255 不能用有符号char类型表示,但您没有分配 255,您分配的是FF,它代表-1.

您想使用uint8_t中定义的stdint.h,或者至少使用unsigned char

于 2012-09-17T21:51:59.203 回答
-1

“实现定义”是 C++ 国际标准的语言,它是一个准法律文件,旨在涵盖所有可能的情况。

因此它可以在 char 为 9 位的机器上运行,因此它在处理二进制数据和文件的行为中固有,某些方面将由实现定义。根据标准的规定,您必须研究每台目标机器的文档,并确保在每种情况下都能实现您需要的行为。

在现实世界中,每个现代通用 CPU 都有 8 位字节并使用 2s 补码算法,因此除非您针对非常特定的情况,否则无需担心。

于 2012-09-17T22:19:56.313 回答