我可以用c ++/g ++做到这一点:
struct vec3 {
union {
struct {
float x, y, z;
};
float xyz[3];
};
};
Run Code Online (Sandbox Code Playgroud)
然后,
vec3 v;
assert(&v.xyz[0] == &v.x);
assert(&v.xyz[1] == &v.y);
assert(&v.xyz[2] == &v.z);
Run Code Online (Sandbox Code Playgroud)
将工作.
如何使用gcc在c中执行此操作?我有
typedef struct {
union {
struct {
float x, y, z;
};
float xyz[3];
};
} Vector3;
Run Code Online (Sandbox Code Playgroud)
但我特别是周围都有错误
line 5: warning: declaration does not declare anything
line 7: warning: declaration does not declare anything
Run Code Online (Sandbox Code Playgroud) 我一直在寻找,但找不到明确的答案.
很多人说使用工会来打字 - 双关语是不明确的和不好的做法.为什么是这样?考虑到你写入原始信息的内存并不仅仅是自己的改变,我看不出为什么它会做任何未定义的任何原因(除非它超出了堆栈的范围,但这不是一个联合问题,这将是糟糕的设计).
人们引用严格的别名规则,但在我看来,就像说你不能这样做,因为你做不到.
如果不打双关语,联盟的意义又是什么呢?我在某个地方看到它们应该被用来在不同的时间使用相同的内存位置来获取不同的信息,但为什么不在再次使用之前删除信息呢?
总结一下:
额外信息:我主要使用的是C++,但想了解它和C.特别是我正在使用工会在浮点数和原始十六进制之间进行转换以通过CAN总线发送.
Stack Overflow问题的一些答案获取浮点数的IEEE单精度位建议使用union
类型双关的结构(例如:将a的位float
转换为a uint32_t
):
union {
float f;
uint32_t u;
} un;
un.f = your_float;
uint32_t target = un.u;
Run Code Online (Sandbox Code Playgroud)
但是,uint32_t
根据C99标准(至少草案n1124),联盟成员的值似乎未指定,其中第6.2.6.1.7节规定:
当值存储在union类型的对象的成员中时,对象表示的字节与该成员不对应但与其他成员对应的字节采用未指定的值.
C11 n1570草案至少有一个脚注似乎暗示不再是这种情况(见6.5.2.3中的脚注95):
如果用于读取union对象的内容的成员与上次用于在对象中存储值的成员不同,则将值的对象表示的适当部分重新解释为新类型中的对象表示形式在6.2.6中描述(一个过程有时被称为''punning'').这可能是陷阱表示.
但是,第C.6.6.1.7节中的案文与C11草案中的C99草案相同.
这种行为在C99下实际上是未指定的吗?它是否在C11中指定?我意识到大多数编译器似乎都支持这一点,但是知道它是在标准中指定还是只是一个非常常见的扩展会很好.
这里是我所遇到的非常简化的问题代码:
enum node_type { t_int, t_double }; struct int_node { int value; }; struct double_node { double value; }; struct node { enum node_type type; union { struct int_node int_n; struct double_node double_n; }; }; int main(void) { struct int_node i; i.value = 10; struct node n; n.type = t_int; n.int_n = i; return 0; }
我不明白的是:
$ cc us.c $ cc -std=c99 us.c us.c:18:4: warning: declaration does not declare anything us.c: In function ‘main’: us.c:26:4: error: ‘struct node’ …
我有两套数据行.它们都是IEnumerable.我想将这两个列表追加/连接到一个列表中.我确信这是可行的.我不想做一个for循环,并注意到两个列表上有一个Union方法和一个Join方法.有任何想法吗?
C/C++中联合的大小是多少?它是最大数据类型的sizeof吗?如果是这样,如果联合的较小数据类型之一处于活动状态,编译器如何计算如何移动堆栈指针?
自从TypeScript引入了联合类型以来,我想知道是否有任何理由声明枚举类型.请考虑以下枚举类型声明:
enum X { A, B, C }
var x:X = X.A;
Run Code Online (Sandbox Code Playgroud)
和类似的联合类型声明:
type X: "A" | "B" | "C"
var x:X = "A";
Run Code Online (Sandbox Code Playgroud)
如果它们基本上服务于同一目的,并且工会更强大和更具表现力,那么为什么需要枚举?
当我阅读ISO/IEC 9899:1999(见:6.5.2.3)时,我看到了一个这样的例子(强调我的):
以下不是有效的片段(因为联合类型在函数中不可见
f
):Run Code Online (Sandbox Code Playgroud)struct t1 { int m; }; struct t2 { int m; }; int f(struct t1 * p1, struct t2 * p2) { if (p1->m < 0) p2->m = -p2->m; return p1->m; } int g() { union { struct t1 s1; struct t2 s2; } u; /* ... */ return f(&u.s1, &u.s2); }
我测试时发现没有错误和警告.
我的问题是:为什么这个片段无效?
该标准定义了Unions不能用作Base类,但是有没有具体的推理呢?据我所知,Unions可以有构造函数,析构函数,成员变量和操作这些varibales的方法.简而言之,Union可以封装可以通过成员函数访问的数据类型和状态.因此,它在大多数常见术语中有资格成为一个类,如果它可以作为一个类,那么为什么它被限制作为一个基类呢?
编辑:虽然答案试图解释推理我仍然不明白联盟作为派生类是如何比联盟只是一个类更糟糕.因此,为了获得更具体的答案和推理,我将推动这一点获得赏金.对已经发布的答案没有违法行为,谢谢!
你有任何恐怖故事要讲吗?GCC手册最近添加了一个关于-fstrict-aliasing的警告并通过联合转换指针:
[...]获取地址,强制生成指针并取消引用结果具有未定义的行为 [强调添加],即使转换使用了联合类型,例如:
union a_union {
int i;
double d;
};
int f() {
double d = 3.0;
return ((union a_union *)&d)->i;
}
Run Code Online (Sandbox Code Playgroud)
有没有人有一个例子来说明这种未定义的行为?
请注意,这个问题不是关于C99标准所说或不说的.它是关于gcc和其他现有编译器的实际功能.
我只是猜测,但一个潜在的问题可能在于设置d
为3.0.因为d
是永远不会直接读取的临时变量,并且永远不会通过"稍微兼容"的指针读取,所以编译器可能不会费心去设置它.然后f()将从堆栈中返回一些垃圾.
我的简单,天真,尝试失败了.例如:
#include <stdio.h>
union a_union {
int i;
double d;
};
int f1(void) {
union a_union t;
t.d = 3333333.0;
return t.i; // gcc manual: 'type-punning is allowed, provided...' (C90 6.3.2.3)
}
int f2(void) {
double d = 3333333.0;
return ((union a_union *)&d)->i; // gcc …
Run Code Online (Sandbox Code Playgroud) unions ×10
c ×7
c++ ×4
c99 ×2
gcc ×2
struct ×2
type-punning ×2
anonymous ×1
c# ×1
c11 ×1
enums ×1
function ×1
ienumerable ×1
inheritance ×1
scope ×1
sizeof ×1
typescript ×1