在C++中以安全的方式将字符*转换为uint8_t*



我有一个(基(类,它有一个虚函数,应该返回一个指针。有两个类派生自此类。

class A{
//...
virtual uint8_t* getPointer(){
}
}
class B: public A{
//...
uint8_t* getPointer() override {
return static_cast<uint8_t*>(myUnsignedChar);
}
private:
unsigned char* myUnsignedChar;
}

class C: public A{
//...
uint8_t* getPointer() override {
//return??
}
private:
char* myChar;
}

B类有一个unsigned char*所以我可以简单地static_cast它给uint8_t*。但是,C类有char*,我不能简单地将其static_castuint8_t*

我有一些问题:

既然 char 不能保证是 8 位,那么为什么编译器不抱怨static_cast<uint8_t*>(myUnsignedChar)呢?如果某些架构中的char恰好是 16 位,那么怎么可能转换为 8 位整数?

我注意到return reinterpret_cast<uint8_t*>(frame.get()->data());会起作用。我知道这是允许的,因为我只是告诉C++读取指向一个(可能是 8 位数据(的指针只是另一回事。也就是说,如果 char 是 8 位,那么我要做的只是读取相同的 8 位,但将它们想象为正数。所以我会把 -127 读作 0,或者类似的东西(取决于负数在我猜的架构中的表示方式(。

那么,我该如何解决这个问题呢?看起来uint8_t*unsigned char*是安全的char是 8 位,而 reinterpret_cast 只有在char是 8 位并且它指向的数据仅由正值组成时才安全。

我该怎么办?

对于此转换,您可以使用单个reinterpret_cast,因为它是不兼容类型之间的转换,它们之间没有单向隐式转换,并且不涉及限定符的丢失。

return reinterpret_cast<uint8_t *>(myChar);

可以使用 C 样式转换表示法:

return (uint8_t *) myChar;

为了防止有人意外更改myChar类型而不考虑转换的后果,我们可以改为:

return reinterpret_cast<uint8_t *>(static_cast<char *>(myChar));

现在,如果myChar变得const char *,静态强制转换将失败,如果myChar变得int *,静态强制转换也将失败。换句话说,我们首先将值static_cast为我们已经期望的类型,然后reinterpret_cast为我们需要的类型。然后,reinterpret_cast使用从这段代码本身可以明显看出的一对精确的类型:很明显,它的输入是一个char *,并且输出是uint8_t *

如果我们经常需要这样的铸件,我们可以像这样使用模板内联函数使它们更符合人体工程学:

// convert from F to T, without stripping qualifiers like const
template <typename T, typename F> inline T to_from_cast(const F &val)
{
return reinterpret_cast<T>(static_cast<F>(val));
}

现在只是:

return to_from_cast<uint8_t, char *>(myChar);

C++ 强制转换表示法通过显式参数实例化模仿模板函数的调用;因此,我们可以使用这些函数编写自己的强制转换。但是,当违反该类型时,编译器诊断不会那么好。

请注意,如果不指定至少一个模板参数,则无法使用to_from_cast; 无法推断T,因为T不会出现在函数签名中,只有F。这里有一个缺点,即只有一个模板参数的to_from_cast<uint_8_t *>(myChar)是有效的表达式。F被推导出为myChar是什么,哎呀!(但请参阅此问题,了解如何抑制模板参数的推导(。不幸的是,具有更好诊断和所有所需类型参数的替代方案是预处理:

#define to_from_cast(T, F, V) (reinterpret_cast<T>(static_cast<F>(V)))

既然 char 不能保证是 8 位,那么为什么编译器不抱怨 static_cast(myUnsignedChar(?

如果您的unsigned char是 8 位,则它与uint8_t的类型相同;uint8_t只是unsigned chartypedef别名。

在具有 9 位字节的系统上,您可能不会有uint8_t;精确宽度类型的可用性是实现定义的。

C 和 C++ 中的对象以字节为单位。根据定义,charunsigned char等字符类型的大小为 1。没有非零大小的对象的大小小于 1。

如果必须编写可移植到此类系统的代码,则代码不能假定uint8_t存在。

最新更新