是否将 C++ 引用从 unsigned char 转换为 double& 安全?

Ric*_*ski 2 c++ casting reference

我正在尝试通过索引查找来实现用于设置各种代码元素的引用“表”。大多数基础变量都是double,但有一些是不同的类型,例如unsigned char

这是一个简化的示例:

static unsigned char foo = 0;     // Variable to set
static unsigned double bar = 0.0; // Variable to set
...
struct tableEntry {
    double& ref; // Reference to one of the above
    double min;
    double max;
};
struct tableEntry entries[] {
    { bar, 0.0, 1.0 },
    { (double&)foo, 0x0, 0xff },
};
Run Code Online (Sandbox Code Playgroud)

尝试通过表格分配栏时,一切正常。

entries[0].ref = 1.0;
Run Code Online (Sandbox Code Playgroud)

这导致entries[0].ref == 1.0, 和bar == 1.0,正如预期的那样。但是,当通过表分配 foo 时......

entries[1].ref = 1.0;
Run Code Online (Sandbox Code Playgroud)

这会以某种方式导致值不匹配,就好像引用无法正确解释,或者甚至没有引用正确的对象。在此分配之后,entries[1].ref == 1,但是foo == 0

这是语言的未定义行为,还是我滥用或滥用某些东西?这可能是标准版本的差异,因为我用 C++17 在 repl.it 上测试了一个类似的例子,它按我的预期工作。使用 Visual Studio 2017 作为编译器,在 MATLAB 中使用我们的目标编译器进行编译时,这无法按预期工作mex

Jan*_*tke 5

将个人读char作 adouble是未定义的行为,因为它违反了类型别名规则,这就是您正在做的事情。从转换char值到一个double使用值static_cast<double>是完全正常的,虽然所定义。

通常可以重新解释doublechar,但仅限于特定场景:

类型别名

每当尝试通过 AliasedType 类型的泛左值读取或修改 DynamicType 类型的对象的存储值时,除非满足以下任一条件,否则行为未定义:

  • [...]
  • AliasedType 是std::byte(C++17 起)、char、 或unsigned char:这允许将任何对象的对象表示检查为字节数组。

(见reinterpret_cast转换

因此,我们可以将double(DynamicType) 视为char[](AliasedType),但不能反过来。考虑这样char一个事实,它正好是 1 个字节大,而且double很可能是 8 个字节大。重新解释引用时剩余 7 个字节的值是多少?它是未定义的。

请注意,在转换引用时,C 样式转换 like(double&)等效于reinterpret_cast<double&>. 我推荐使用显式的C ++类型转换喜欢const_castreinterpret_cast并且static_cast以避免混淆。