我可以打印整数的地址和值,但不能打印 union 的字符。为什么会这样
#include <iostream>
using namespace std;
union Endian
{
int i;
char c[sizeof(int)];
int j;
};
int main(int argc, char *argv[]) {
Endian e;
e.i = 20;
cout << &e.j;
cout << &e.i;
cout << &e.c[0]; //Why can't I print this address
cout << e.c[1]; // Why can't I print this value
}
O/P:0x7fff5451ab68 0x7fff5451ab68
最佳答案
免责声明:OP 的标签非常含糊,所以这个答案使用代码作为引用框架,即 C++(使用 iostream
,拉入 std
命名空间,cout
)。
您正在使用 union
以不适当的方式。但我们稍后再谈。
e.i = 20;
您的代码首先使用 union 作为
i
,一个整数。哪个没问题。但是你后来的做法真的不是什么好主意。首先你做了两件可以接受的事情:cout << &e.j;
cout << &e.i;
你查询了两个
int
的地址s 在 union 中,这稍微好一点,因为它们都共享存储,因此第一个字节的地址是共享的。cout << &e.c[0]; //Why can't I print this address
cout << e.c[1]; // Why can't I print this value
现在,这就是你越界的地方。您现在正在执行隐式指针算术并在索引到
char[]
方面取消引用。数组,即使您试图获取第一个元素的地址,也可能会评估一个元素,该元素不是 union 中的最后一个集合。所以,这是一个很大的禁忌。此外,
&e.c[0]
基本上是char*
它将被 cout
“拦截”并被视为 C 风格的字符串。它不会把它当作一个简单的地址。cout << e.c[1]; // Why can't I print this value
未定义的行为。 “可是,可是!” ,我能听到你们中的一些人说。是的,它是 C++ 中的 UB。在 C99 (6.5/7) 中有效,只需通过脚注和一些胶带即可。这是一个简单的问题,LightnessRacesInSpace 和 Mysticial 在这个答案和其他人的评论中已经解释过。
是的,您可以将您拥有的任何类型化变量转换为 char 数组,并出于您的任何目的使用它。但是通过 union 进行类型转换在 C++ 中是非法的,没有任何借口和借口。是的,它可能会起作用。是的,如果你不介意的话,你可以继续使用它。但是按照 C++ 标准,这显然是非法的。
除非该成员是您为其分配值的 union 的最后一个成员,否则您不得检索其值。就这么简单。
C++ 中的 union 有一个目的,如下所述。它们还可以具有成员函数和访问说明符。它们不能有虚函数或静态成员。它们也不能用作基类或从某些东西继承。它们不能用于类型双关。在 C++ 中这是非法的。
进一步阅读!
了解 union
union 是:
union 不是:
甚至 MSDN 也做对了:
A union is a user-defined data or class type that, at any given time, contains only one object from its list of members (although that object can be an array or a class type).
这是什么意思?这意味着您可以按照以下方式定义一些内容:
union stuff {
int i;
double d;
float f;
} m;
这个想法是他们都坐在内存中的同一个空间。 union 的存储是从给定实现中最大的数据类型推断出来的。平台在这里有很多自由。规范无法涵盖的自由。不是 C。不是 C++。
您绝不能以
int
的身份写信给 union 然后将其读作 float
(或其他任何东西)作为某种奇怪的牛仔 reinterpret_cast 的一种方式。std::cout
的使用是为了示例目的和简单性。 这是非法的:
m.i = 5;
std::cout << m.f; // NO. NO. NO. Please, no.
这是合法的:
m.i = 5;
std::cout << m.i;
// Now I'm done with i, I have no intention of using it
// If I do, I'll make sure I properly set it.
m.f = 3.0f;
std::cout << m.f; // No "cowboy-interpreting", defined.
// I've got an idea, but I need it to be an int.
m.i = 3; // m.f and m.d are here-by invalidated.
int lol = 5;
m.i += lol;
请注意没有“交叉火力”。这是预期用途。在三个不同时间使用的三个变量的超薄内存存储,没有冲突。
误解是如何产生的?有一天,一些非常坏的人醒来,我敢打赌其中一个是 3D 程序员,并考虑过这样做:
// This is wrong on so many different levels.
union {
float arr[4];
struct {
float x,y,z,w;
};
};
毫无疑问,他有一个“高尚的想法”,以浮点数组和单独的 xyzw 成员的形式访问 4 元组。现在,您知道为什么在 union 方面这是错误的,但这里还有一个失败:
C++ 没有匿名结构 .它确实有匿名 union ,用于上述目的,使其更接近预期用途(删除
m.
“前缀”),因为您肯定可以看到这如何有益于 union 背后的一般思想。不要这样做。请。
关于c++ - 在 union 中使用字符数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15952204/