我有一个(基(类,它有一个虚函数,应该返回一个指针。有两个类派生自此类。
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_cast
uint8_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 char
的typedef
别名。
在具有 9 位字节的系统上,您可能不会有uint8_t
;精确宽度类型的可用性是实现定义的。
C 和 C++ 中的对象以字节为单位。根据定义,char
和unsigned char
等字符类型的大小为 1。没有非零大小的对象的大小小于 1。
如果必须编写可移植到此类系统的代码,则代码不能假定uint8_t
存在。