为什么fstream.read和fstream.write使用char而不是unsigned char?

3
据我所知,read()write() 存在的目的是为了我们能够直接从文件中读取和写入字节,我曾被教导过,在 c++ 中,byte 的等效类型是 unsigned char,那么为什么它们要将 char 指针作为参数呢?
此外,请看一下我找到的“bmp 文件图像阅读器”库中的这个函数:
bool BMPImage::readInfo()
{
    //...

    //read bmp and dib headers
    unsigned char header[28] = {0};
    _ifs->read((char*)header, 28);
    _width    = *(int*)&header[18]; //width is located in [18] and is 4 bytes size
    _height   = *(int*)&header[22]; //height is located in [22] and is 4 bytes size
    _bpp      = (unsigned char) *(short*)&header[28]; //bpp is located in [28] and is 2 bytes size
    _channels = _bpp / 8; //set num channels manually

    //...

为什么_ifs->read()这行代码能够正常工作?将unsigned char强制转换为char会导致数据丢失,不是吗?

3
将无符号字符转换为字符会导致数据丢失,对吗? - 不是。 - user2100815
charunsigned char 的大小相同,都是 1 字节。唯一的区别在于有无符号:unsigned char 总是 > 0;而普通的 char 可以是有符号的(但不一定)。 - Ben Steffan
charunsigned char 之间没有实际区别。但由于大多数人在程序中使用 char,因此 API 接受最常用的类型是很自然的事情。 - SergeyA
1
我可以将unsigned char转换为char,反之亦然吗? - wally
更好的问题是:为什么不是void*?这样,我就可以隐式地将数据读入任何指针中,而无需进行reinterpret_cast。 - Calmarius
3个回答

1
在C和C++中,标准没有规定char是有符号的还是无符号的,实现可以自由地将其实现为任意一个。有两种不同类型的signed char(保证至少能够容纳范围[-127,127])和unsigned char(保证至少能够容纳范围[0,255]),而char将等同于其中的一种,但是对于它是哪一种,这是由实现定义的。
考虑到ASCII字符集仅包含值0到127,因此从历史上看,一个有符号字节足以容纳单个字符,同时仍使用与较大类型相同的约定,即除非显式声明为unsigned,否则整数类型默认为有符号的。

0

鉴于 charunsigned char 具有相同的大小,因此在它们之间进行转换时不应该有数据丢失。

但是需要注意的是,fstreamm 只是针对字符的 std::basic_fstream 的特化:

// from <fstream>
typedef basic_fstream<char>         fstream;

您可以创建自己的无符号字符类型,例如:
typedef basic_fstream<unsigned char> ufstream; 

在执行这些文件IO操作时,使用C风格的转换是否可行?此外,为什么这些函数仍然使用char而不是unsigned char,甚至是void*作为C语言等效物呢? - McLovin

0
在C ++中,byte 的等效之处被教导为 unsigned char
我不知道什么是 byte,但可以使用 char 来很好地表示一个 bytefstreamstd::basic_fstream<char> 的别名。 std::basic_fstream 是一个模板,其所有操作都涉及其指定的char_type。 由于该char_typechar,因此所有操作都涉及char而不是unsigned char
你可以像Juan建议的那样使用basic_fstream<unsigned char>,但这比那更复杂。 您需要专门化basic_fstream<unsigned char>的第二个(默认)模板参数,即char_traits<unsigned char>
从无符号字符到字符的转换会强制丢失数据,不是吗?

不会。通过 char* 访问 unsigned char 不会丢失任何数据。实际上,通过 char* 访问任何类型都不会丢失数据。


而另一方面,这是:

*(int*)&header[18]

除非缓冲区被正确对齐,使得header[18]恰好位于int所需的边界上,否则将产生未定义的行为。我在数组的定义中没有看到这样的保证。有些架构根本不支持不对齐的内存访问。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接