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

时间:2019-09-12 00:15:31

标签: c++

我有一个带有虚拟函数的(基)类,该虚函数应该返回一个指针。从该类派生两个类。

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位并且其指向的数据仅由正值。

我该怎么办?

1 个答案:

答案 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 charuint8_t这样的字符类型的大小为1。没有非零大小的对象的大小小于1。

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

相关问题