使用指针将char*转换为unsigned char*的强制类型转换

11

我正在编写一些使用fstream read()函数的代码,该函数期望一个char*作为缓冲区。稍后,我希望使用该缓冲区中的字节作为无符号字符进行操作,因此我要么:1. 声明缓冲区为char*,然后稍后对每个元素进行static_cast 2. 声明缓冲区为unsigned char*,然后在将其传递给读取函数时进行reinterpret_cast,或者3. 声明缓冲区为char*,并创建一个转换后的指针用于以unsigned char的形式访问缓冲区。

这是一个片段:

char* buf = new char[512];
unsigned char* ubuf = reinterpret_cast<unsigned char*>(buf);

    fstream myfile;

    myfile.open("foo.img");

    myfile.seekg(446);
    myfile.read(buf, 16);
    //myfile.read(reinterpret_cast<char*>(buf), 16);

int bytes_per_sector = ubuf[1] << 8 | ubuf[0];
...

我喜欢这种方式,因为我只需要转换一次类型,就可以随意访问缓冲区而无需每次进行类型转换。但是,这样做是否是一个好的实践?这里有什么问题吗?使用reinterpret_cast使我有点紧张,因为我平时不怎么用它,并且被告知要小心使用它很多次。


1
这是极少数情况之一,reinterpret_cast 实际上是安全且有意义的。 - Konrad Rudolph
5
请不要推荐使用 C 风格的强制类型转换,因为它在 C++ 中已经被视为过时了。尽管在这种情况下使用是安全的,但最好禁止使用它们,以避免潜在的混淆。而且,reinterpret_cast 更加明确,使代码更易读,因为它清楚地告诉读者正在执行哪种类型转换。 - Konrad Rudolph
4
C++的强制类型转换运算符替代了 C 语言风格的类型转换。由于总是可以使用更具体的 C++ 强制类型转换,因此使用 C 风格的类型转换既没有帮助也没有理由。永远不应使用 C 风格的类型转换。你提到的“可能会更加简洁”没有意义,因为:1. C 风格的类型转换只能执行合适的 C++ 强制类型转换所能做的事情; 2. 在这种情况下,它什么也做不了。 - philipxy
1
@Deduplicator 我们两个想表达的观点是,即使不考虑类型安全性,reinterpret_cast 也是显式的,因此可以增加可读性。 reinterpret_cast 具有明确定义的含义。 相比之下,C风格的转换则没有。 它可以表示许多事情,因此在代码中使用它会使实际语义对读者变得模糊。 这通常被认为是一个极其糟糕的想法。 - Konrad Rudolph
1
现在,如果我需要重新设计C ++,我会喜欢将c-style-cast降级为implicit,将function-style降级为implicit+任何ctor+conversion-operator(遗憾的是implicit_cast不在C ++14中),并使其他4种类型(static,const,dynamic,reinterpret)成为简短而简洁的变体。 - Deduplicator
显示剩余7条评论
1个回答

11
在这种情况下,使用reinterpret_cast是可以的,有两个原因:
  1. (有符号)char和unsigned char类型需要具有相同的"表示和对齐方式"。这意味着数据不会有任何差异(它将是逐位完全相同的),或者缓冲区的解释方式有多长。

  2. 文件读取函数通常只使用char*作为通用数据访问类型。他们不能使用void*,因为类型void具有明确定义的长度和表示形式。而char则有。所以他们可以使用它来读/写一系列字节。

实际上,文件函数经常旨在将数据重新解释为其他东西。这使您可以拥有像结构体这样的东西

typedef struct structSomeStruct
{
    char name[8]; // a basic, fixed length, string
    unsigned long i; // a 32 bit value
    float x, y, z, w;
} SomeStruct;

或者

class SomeStruct
{
    public:
        char name[8];
        unsigned long i;
        float x, y, z, w;
        
        SomeStruct()
        {
            // ...
        }
};

并使用类似以下方式将其存储到文件中:

SomeStruct st;

// populate the st data structure

// file.write(char* start_of_data, size_t number_of_bytes);
file.write(reinterpret_cast<char*>(&st), sizeof(SomeStruct));

同样地阅读它。


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