c++ - 在 C++ 中以安全的方式将 char* 转换为 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_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 或类似的东西(取决于我猜负数在体系结构中的表示方式)。
那么,我该如何解决这个问题呢?看起来只有 8 位是安全的unsigned char*
,并且 reinterpret_cast 只有在8 位并且它指向的数据仅由正值组成时才是安全的。uint8_t*
char
char
我应该怎么办?
解决方案
对于此转换,您可以使用 single 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 *
,它也会失败。换句话说,我们首先将值设置为我们已经期望的类型,然后设置为我们需要的类型。then 可以使用从这段代码本身可以明显看出的一对精确类型:很明显,它的输入是 a ,输出是。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
只是. typedef
_unsigned char
在具有 9 位字节的系统上,您可能不会有uint8_t
; 精确宽度类型的可用性是实现定义的。
C 和 C++ 中的对象以字节为单位。根据定义,字符类型char
和unsigned char
大小为 1。没有非零大小的对象的大小小于 1。
如果您必须编写可移植到此类系统的代码,则您的代码不能假定uint8_t
存在。
推荐阅读
- c# - 在控制台应用程序中使用 WindowsFormsSynchronizationContext 时出现异步/等待死锁
- google-bigquery - BigQuery 中按键(或对称聚合)函数求和不同
- javascript - 如何一次只切换一个按钮 onclick?
- python - 如何在 cython 纯模式下循环列表
- xml - 创建一个属性并使用节点值 xslt 填充它
- javascript - 如何修复反应功能不起作用(机器人重新启动后)
- python - 从python中的整数列中删除空格
- php - PHP:如何管理 simplexml_load_string() 上的“文档标记为 UTF-16 但具有 UTF-8 内容”错误
- .htaccess - 使用 .htaccess,如何显示另一个 URL 的内容,就好像它是当前 URL
- php - Wordpress Cron 作业未运行