将指向typed/size enum的指针转换为指向底层类型的指针是否安全?

Lui*_*uis 10 c++ enums pointers implicit-conversion c++11

以下代码:

void f(const uint8_t* a) {}  // <- this is an external library function
enum E : uint8_t { X, Y, Z };

int main(void) {
  E e = X;
  f(&e);  // <- error here
}
Run Code Online (Sandbox Code Playgroud)

产生以下错误:

/tmp/c.cc:10:3: error: no matching function for call to 'f'
  f(&e);
  ^
/tmp/c.cc:5:6: note: candidate function not viable: no known conversion from 'E *' to 'const uint8_t *' (aka 'const unsigned char *') for 1st argument
void f(const uint8_t* e) { }
Run Code Online (Sandbox Code Playgroud)

这对我来说是令人惊讶的,因为我认为: uint8_t枚举的定义意味着它们必然以底层类型表示.我可以通过演员轻松解决这个问题:

f((uint8_t*)&e);
Run Code Online (Sandbox Code Playgroud)

我不介意太多,但鉴于省略它是一个错误,这总是安全的还是: uint8_t不提供我认为的保证?

ein*_*ica 6

这确实是安全的(虽然我不是语言律师):存储在内存中的是什么uint8_t,这就是你要指的是什么.但是,如果f()要将指针指向非const uint8_t,那么它可能会将值更改为未明确定义为E枚举值之一的值.(编辑:)虽然这显然是C++标准所允许的,但对于许多人来说这是令人惊讶的(参见下面关于这一点的评论中的讨论),我鼓励你确保它不会发生.

...但正如其他人所说,由于你的安全概念,你没有得到错误,而是因为在指向类型之间不执行隐式转换.你可以把E一个函数传递给一个函数uint8_t,而不是E *一个函数取一个uint8_t *; 那将是 - 根据语言委员会和我认为 - 对指针类型过于傲慢的态度.


Mik*_*eMB 5

Afaik 这只是偶然的合法:

您正在做的是执行 areinterpret_cast并且我假设f是在内部取消引用该指针。这仅在非常有限的情况下是合法的,虽然不规范,但cppreference.com对这些情况进行了很好的概述:

当动态类型为 DynamicType 的对象的指针或引用被 reinterpret_cast(或 C 样式转换)到不同类型 AliasedType 的对象的指针或引用时,转换总是成功,但结果指针或引用只能用于如果以下情况之一为真,则访问该对象:

  • AliasedType 是(可能是 cv 限定的)DynamicType

  • AliasedType 和 DynamicType 都是(可能是多级的,可能在每一级都有 cv 限定)指向相同类型 T 的指针(C++11 起)

  • AliasedType 是 DynamicType 的(可能是 cv 限定的)有符号或无符号变体

  • AliasedType 是聚合类型或联合类型,它将上述类型之一作为元素或非静态成员(递归地包括子聚合的元素和所包含联合的非静态数据成员):这使得获得给定指向其非静态成员或元素的指针,指向结构或联合的可用指针。

  • AliasedType 是 DynamicType 的(可能是 cv 限定的)基类,DynamicType 是没有非静态数据成员的标准布局类,AliasedType 是它的第一个基类。

  • AliasedType 是 char、unsigned char 或 std::byte:这允许将任何对象的对象表示作为字节数组进行检查。

如果 AliasedType 不满足这些要求,则通过新指针或引用访问对象会调用未定义的行为。这被称为严格别名规则,适用于 C++ 和 C 编程语言。

这些情况都不包括转换为指向枚举底层类型的指针!

但是:
转换为指向unsigned char*并取消引用它的指针始终是合法的,并且在大多数平台uint8_t上只是一个 typedef。所以在这种情况下是可以的,但如果基础类型(例如)是uint16_t.

话虽如此,听到大多数编译器允许这样的用法,我不会感到惊讶,即使标准不允许。