【问题标题】:Is the behaviour for a runtime bad C-style cast defined?是否定义了运行时错误的 C 样式强制转换的行为?
【发布时间】:2016-12-31 21:58:37
【问题描述】:

如果您将旧的 C 风格从 A 类型转换为 B 类型,而 A 类型不能转换为 B 类型,反之亦然,C++ 标准是否定义了特定的行为?

是否存在已知的可见行为,可以被认为是运行时非法强制转换的症状?

【问题讨论】:

  • 我认为你应该提供一个例子。例如:您是在谈论 POD 类型、类、原始类型、指针……吗?
  • C 风格的转换可以等效于 3 种不同的 C++ 转换(static_castreinterpret_castconst_cast)中的任何一种,具体取决于实际代码。其中static_cast 会引发编译时错误,而reinterpret_cast 会(在大多数情况下)导致 UB(如果强制转换是非法的)
  • 您可能会发现您得到“未定义的行为”,并且“未定义的行为”没有标准症状 - 程序的行为与您预期或预期的不同,但这就是您的全部可以说。使用某些编译器,它甚至可能会像您预期的那样运行;尽管有可能,但它们中的任何一个都没有义务出错。
  • 如果没有从 A 到 B 的等效 c++ 转换,则 c 样式转换将失败。
  • @MikeMB 失败是指编译时错误还是未定义的运行时行为?因为正如其他答案所述,您实际上可以在等效转换是非法的 c 风格中进行转换。

标签: c++


【解决方案1】:

四种 C++ 风格的类型转换中只有一种决定了运行时类型转换的有效性,即dynamic_cast

C 风格的转换对应于其他三个转换的组合(static_castreinterpret_castconst_cast)。这些转换的有效性在编译时确定,或者如果在编译时无法确定,则假定转换是有效的。 C 风格的演员表永远不会像dynamic_cast 那样行事。

因此,在运行时“失败”的 C 样式转换,即打破有效性假设,会导致未定义的行为。所以:

如果您将旧的 C 风格从 A 类型转换为 B 类型,而 A 类型不能转换为 B 类型,反之亦然,C++ 标准是否定义了特定的行为?

没有。

是否存在已知的可见行为,可以被认为是运行时非法强制转换的症状?

没有。

【讨论】:

  • 谢谢,这就是我想知道的全部内容
  • Also see here,这种 C 风格的转换不等同于 C++ 风格的转换的任何组合
【解决方案2】:

编译器会捕获其中的一些,但不是全部。这是一个灾难性演员阵容的例子:

#include <iostream>
#include <string>

using namespace std;

class A {
public:
        A(std::string s, int x) : m_s(s), m_x(x) {} 

        void print() { cout << "A::print(): str = " << m_s << ", x = " << m_x << endl; }

private:  
        std::string m_s;
        int m_x;
};

class B {
public:
        B(int x) : m_x(x) {}
        void print() { m_x++; cout << "B::print(): x = " << m_x << endl; }

private:
        int m_x;

};

int main(int argc, char **argv) {

        A *a = new A("abc", 1);
        a->print();
        B *b = (B*)a;
        b->print();

        a->print();

        return 0;
}

在 gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609 上的结果:

A::print(): str = abc, x = 1
B::print(): x = 24828977
A::print(): str = bc, x = 1

是的,我们在 A 的数据上调用了 B 的方法,这意味着我们的 C 样式转换为 reinterpret_castreinterpret_cast 只占用一个内存区域并允许您将其视为不同的东西。这里没有安全带。

另一方面,如果你尝试编译这样的东西

    A a;
    B b;
    a = (A)b;
    return 0;

这将导致static_cast 和编译时错误。所以 C 风格的转换结果取决于上下文。

这是处理模板和auto 时的噩梦。

为避免此问题,请使用static_cast(用于编译时检查)和dynamic_cast(用于运行时检查)或reinterpret_cast(用于指针和POD),明确说明您的意图。

【讨论】:

  • 实际上你的结果可能只出现在你的机器/编译器上——我得到一个runtime errorb-&gt;print(); 行正在调用 undefined behavior
  • B::print() 修改sizeof(int)std::string 占用的字节。您可能会在那里观察到内存损坏。
  • documentation of reinterpret_cast 对此很清楚 - 您正在调用 UB。也不确定内存损坏对您的结果无法保证以及不同的编译器引发运行时错误这一事实有何影响。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-28
  • 1970-01-01
  • 1970-01-01
  • 2018-03-15
相关资源
最近更新 更多