我有一个带有虚拟函数的(基)类,该虚函数应该返回一个指针。从该类派生两个类。
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,或类似的值(取决于我猜想的体系结构中负数的表示方式)。
那么,我该如何解决这个问题?看起来unsigned char*
至uint8_t*
是唯一安全的,只有char
是8位,而reinterpret_cast仅在char
是8位并且其指向的数据仅由正值。
我该怎么办?
答案 0 :(得分:3)
对于此转换,您可以使用单个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 *
,输出是{{1} }。
如果我们经常需要此类转换,则可以使用模板内联函数使它们更符合人体工程学:
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));
}
C ++强制转换符号模仿带有显式参数实例化的模板函数的调用;因此,我们可以使用此类函数编写自己的演员表。但是,当违反类型时,编译器的诊断将不会那么好。
请注意,如果不指定至少一个模板参数,则无法使用return to_from_cast<uint8_t, char *>(myChar);
;无法推论to_from_cast
,因为T
不会出现在函数签名中,只有T
才会出现。这里的缺点是F
仅具有一个模板参数是有效的表达式。 to_from_cast<uint_8_t *>(myChar)
被推导为F
,哎呀! (但请参见this question,了解如何抑制模板参数的推论)。不幸的是,具有更好的诊断和所有类型参数要求的替代方法是预处理:
myChar
因为不能保证char为8位,那么为什么编译器不会抱怨static_cast(myUnsignedChar)?
如果您的#define to_from_cast(T, F, V) (reinterpret_cast<T>(static_cast<F>(V)))
是8位,则它与unsigned char
的类型相同; uint8_t
只是uint8_t
的{{1}}别名。
在具有9位字节的系统上,您可能没有typedef
;精确宽度类型的可用性由实现定义。
C和C ++中的对象以字节为单位。根据定义,像unsigned char
和uint8_t
这样的字符类型的大小为1。没有非零大小的对象的大小小于1。
如果您必须编写可移植到此类系统的代码,则您的代码不能假定char
存在。