我能够打印出int的地址和值,但不能打印出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
}
Run Code Online (Sandbox Code Playgroud)
O/P:0x7fff5451ab68 0x7fff5451ab68
小智 19
免责声明:OP的标签非常模糊,因此这个答案使用代码作为参考框架,即C++(使用iostream,拉入std命名空间cout).
你union以不恰当的方式使用.但我们稍后会再回过头来看看.
e.i = 20;
Run Code Online (Sandbox Code Playgroud)
您的代码首先使用union作为i整数.哪个没关系.但是你之后所做的并不是一个好主意.首先,你做了两件有些可接受的事:
cout << &e.j;
cout << &e.i;
Run Code Online (Sandbox Code Playgroud)
您查询了int联合中两个s 的地址,这是很小的,因为它们都共享存储,因此共享第一个字节的地址.
cout << &e.c[0]; //Why can't I print this address
cout << e.c[1]; // Why can't I print this value
Run Code Online (Sandbox Code Playgroud)
现在,这是你越过界限的地方.您现在正在执行隐式指针算法和解引用方面的索引到char[]数组中,即使您尝试获取第一个元素的地址,也可能会评估一个元素,该元素不是联合中设置的最后一个元素.所以,这是一个很大的禁忌.
此外,&e.c[0]基本上char*它将被"拦截"并被cout视为C风格的字符串.它不会将其视为简单的地址.
cout << e.c[1]; // Why can't I print this value
Run Code Online (Sandbox Code Playgroud)
未定义的行为."但是,但是!" ,我听到你们有些人说.是的,它是C++中的UB.在C99(6.5/7)中有效,并且几乎没有通过脚注和一些胶带.这是一个简单的问题,LightnessRacesInSpace和Mysticial已经在这个答案和其他人的评论中解释过了.
是的,您可以将任何类型的变量转换为char数组并将其弄乱,无论出于何种目的.但是在C++中通过工会打字是非法的,没有任何问题和借口.是的,它可能会奏效.是的,如果你不为它烦恼,你可以继续使用它.但根据C++标准,这显然是非法的.
除非该成员是您为其分配值的联合的最后一个成员,否则您不应检索其值.就这么简单.
C++中的联合有一个目的,如下所述.它们还可以具有成员函数和访问说明符.他们不能拥有虚拟功能或静态成员.它们既不能用作基类,也不能从某些东西继承.而且它们不能用于打字.这在C++中是非法的.
进一步阅读!
工会是:
工会不是:
即使是MSDN也是如此:
union是用户定义的数据或类类型,在任何给定时间,它只包含其成员列表中的一个对象(尽管该对象可以是数组或类类型).
这是什么意思?这意味着您可以按照以下方式定义某些内容:
union stuff {
int i;
double d;
float f;
} m;
Run Code Online (Sandbox Code Playgroud)
这个想法是他们所有人都坐在记忆中的同一个空间.从给定实现中的最大数据类型推断出联合的存储.平台在这里有很多自由.自由规格无法涵盖.不是C.不是C++.
你不能写作联盟作为一个int,然后把它作为一个float(或其他任何东西)读作一种奇怪的牛仔reinterpret_cast的方式.
使用std::cout是出于示例目的和简单性.
m.i = 5;
std::cout << m.f; // NO. NO. NO. Please, no.
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
注意没有"交火".这是预期用途.超薄内存存储三个不同时间使用的三个变量,没有战斗.
错误概念是如何上升的?有些非常糟糕的人有一天醒来,我打赌他们中的一个是3D程序员,并考虑过这样做:
// This is wrong on so many different levels.
union {
float arr[4];
struct {
float x,y,z,w;
};
};
Run Code Online (Sandbox Code Playgroud)
毫无疑问,他有一个"高贵的想法",可以作为浮动阵列和单独的xyzw成员获得4元组.现在,你知道为什么这在工会方面是错误的,但这里还有一个失败:
C++没有匿名结构.它确实有匿名联盟,出于上述目的,使其更接近预期用途(删除m."前缀"),因为你可以肯定地看到它如何有利于工会背后的一般理念.
不要这样做.请.