【问题标题】:How to convert between int * and enum *?如何在 int * 和 enum * 之间转换?
【发布时间】:2018-01-22 08:33:24
【问题描述】:

从一些 C 遗留代码中,我得到了一些常量 int *。在 C++ 部分,我有一个基础类型 int 的枚举。基于单个值的枚举和 int 之间的转换有效。但是,int *enum * 之间的转换是不可能的。请参阅下面的代码示例。

为什么会这样?如何将指向某些 int 值的指针转换为指向 int 枚举的指针,反之亦然?我有点希望它能够工作,因为单值转换工作并且基础类型是相同的。我阅读了有关 What happens if you static_cast invalid value to enum class? 的信息,但无法确定潜在的无效值是否在这里起作用。

int i = 3;
enum E : int;
E e;

e = static_cast<E>(i);   // ok
i = static_cast<int>(e); // ok

int *j;
E * f;

j = static_cast<int *>(&i); // ok
f = static_cast<E *>(&i);   // 'static_cast': cannot convert from 'int *' to 'E *'
j = static_cast<int *>(&e); // 'static_cast': cannot convert from 'E *' to 'int *'

// now use j and f
*j = *f;

【问题讨论】:

  • 你试过reinterpret_cast吗?
  • 虽然您可以使用reinterpret_cast 进行转换,但这样做很少有用。如果不调用未定义的行为,则无法取消引用结果指针。
  • @davmac 似乎我应该确保关闭严格的别名规则或开始考虑复制。感谢答案和答案下面的讨论,我现在更好地理解了。

标签: c++ c++11 enums


【解决方案1】:

这是为什么呢?

从编译器的角度来看,int*E* 是不同的非相关类型的指针,这就是为什么static_cast 在这里不适用。

如何将指向某些 int 值的指针转换为指向 int 枚举的指针,反之亦然?

您可以尝试reinterpret_cast 而不是static_cast

f = reinterpret_cast<E *>(&i);
j = reinterpret_cast<int *>(&e);

来自reinterpret_cast

任何指向 T1 类型对象的指针都可以转换为指向另一个类型 cv T2 的对象的指针

但是,请注意,取消引用 fj(即使用 *f*j)将违反严格的别名规则(有关详细信息,请参阅讨论以下)。这意味着这种转换虽然严格可行,但通常没有用。

【讨论】:

  • 值得注意的是,虽然这“有效”,但很可能是严格的别名违规。
  • 我同意 reinterpret_cast 解决了这个问题。但是我想知道为什么 int* 和 E* 不同,而 int 和 E 则不同。无论如何,将标记为已解决。
  • @Trilarion 在某些情况下使用static_cast 是合法的,它们被明确列出。从形式上讲,您的案例不属于这些案例中的任何一个,所以...您必须改用reinterpret_cast
  • @user2079303 它 100% 是一个严格的别名违规,这是证明:godbolt.org/g/pekQNX(参见add eax, eax。它假设两个指针不能被别名)
  • @user2079303 我在标准中找不到任何东西(至少在 N3690 中),它允许将枚举类型视为与其基础类型的 相似 类型(也没有任何其他允许用于通过底层类型引用访问枚举对象)。如果您可以指出标准中的任何相关内容,很高兴被证明是错误的 :) [编辑:虽然我不认为上面显示的 GCC 行为是 100% 的证明,但我真的相信标准不允许这种形式的类型双关]
【解决方案2】:

枚举的默认“基本类型”是int,可以在 OP 中明确指定。从逻辑上讲,存储在E* e 的值是一个int 的基本类型为int 的枚举。不能静态转换。

在 C++ 中不能保证基本类型的 enumshort 的布局兼容,但即使语言加强了这一点,也可能存在类型兼容性问题/

一个问题是E*int*pi 会违反类型安全,因为pi 可用于在枚举之外悄悄地设置值。 同样,如果整数值不在枚举中,int*E* 可能会违反类型安全。

但请注意,该标准明确指出,没有什么可以阻止枚举在其定义的值集之外获取值:

这组值用于定义枚举类型的提升和转换语义。它不排除一个 枚举类型表达式的值超出此范围。

请参阅此处:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf(请参阅第 156 页底部的注释 95)

唯一可以(如果保证布局兼容性)有效的情况是E*const int*,因为E* 的所有值都是ints,并且该值不能(正确)通过@ 修改987654337@指针没有进一步违反类型系统。

但我认为语言定义没有那么微妙。

【讨论】:

  • “逻辑上存储在 E* e 的值,其中 E 是一个基本类型为 int 的枚举”,而(我认为)我知道你的意思,我认为这样说可能会产生误导.没有正式的保证枚举的表示与其基类型的表示相对应(或者我不知道,没有彻底检查过)。另外:“pi 可用于在枚举之外悄悄地设置值”——通过 int * 这样做也违反了严格的别名规则。
  • 没有声明枚举与其“基本类型”或“基础类型”(AFAIK)“布局兼容”。我正在完善声明。我建议这里的标准是不必要的限制。特别考虑到注释'这组值用于定义枚举类型的提升和转换语义。它不排除枚举类型的表达式具有超出此范围的值。'。从我可以看到一个实现可以使用int,即使是一个基本类型为short的枚举。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-20
  • 2017-08-25
  • 2014-01-29
  • 2011-06-28
  • 2010-10-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多