求C联盟清晰度

时间:2010-05-20 11:37:49

标签: c unions

typedef union {
    float flts[4];
    struct {
        GLfloat r;
        GLfloat theta;
        GLfloat phi;
        GLfloat w;
    };
    struct {
        GLfloat x;
        GLfloat y;
        GLfloat z;
        GLfloat w;
    };
} FltVector;

好的,所以我想我得到了如何使用它,(或者,这就是我看到它的使用方式)即。

FltVector fltVec1 = {{1.0f, 1.0f, 1.0f, 1.0f}};
float aaa = fltVec1.x;
etc.

但是我并没有真正意识到联盟宣布了多少存储量(4个花车?8个花车?12个花车?),怎么样?为什么?还有为什么在使用FltVector {{}}时会有两组大括号?

为什么要使用工会呢?为什么不这样做..

   struct FltVector {
        GLfloat x;
        GLfloat y;
        GLfloat z;
        GLfloat w;
   }

任何指针都非常赞赏(对不起双关语)

6 个答案:

答案 0 :(得分:5)

union允许您为不同类型的变量“回收”相同的内存区域。通常,union会占用与其单个最大成员一样多的存储空间,在这种情况下可能需要4个浮点数。您可以查看sizeof

在这种情况下,union可能用于为结构中的相同浮点数提供1)替代名称(例如xr共享相同的内存),以及2)访问< em>相同四个浮点数作为数组(例如xflts[0]共享相同的内存)。有时,工会被用在各种“黑客”中,通常是非便携的,以访问某些数据类型的内部,例如,机器顺序中整数的单个字节。

答案 1 :(得分:5)

如果sizeof(GLfloat) == sizeof(float)那么,已经分配了4个浮点数。

flts[0]rx都将在此处引用相同的内存。

在union中,union中声明的每个不同变量都指向同一块内存。

这里我们有3个变量,2个结构和一个数组,每个变量都从内存中的同一点开始。

答案 2 :(得分:2)

那里有几个问题:)

@Arkku的大小是正确的。对齐也可以发挥作用,但可能不在这里。

为什么这是真的,在任何给定时间,联合只保留一个可能的值。出于这个原因,将结合放在一个结构中以及标识哪个值有效的东西(有时称为区分联合 scrim )是很常见的。

一对括号用于联合,另一对用于阵列初始化。

答案 3 :(得分:1)

  

为什么在使用FltVector {{}}

时有两组大括号

看看整行,FltVector fltVec1 = {{1.0f, 1.0f, 1.0f, 1.0f}}; 您正在初始化联合中第一个结构 中的四个浮动 。从粗体“in”中可以看出,嵌套有两个层次。如果嵌套的级别更深,你甚至可以有更多的花括号。

答案 4 :(得分:1)

在你的例子中,如果我们考虑变量的名称,联合肯定不会用来通过说x和r来访问同一个内存单元(因为半径和x坐标不合适),但是让用户为两者提供相同的参数。当你使用笛卡尔坐标时设置x,y,z,w要简单得多,并且在径向坐标上使用这些相同的名称会很尴尬。两者都比数组索引简单。您可能还有另一个参数,它给出了所提供坐标的类型(笛卡尔坐标或径向坐标)。因此,当pdbartlett调用它们时,你将拥有一个有区别的联盟。

在这种情况下,双层括号是无用的,因为数组可以通过数组(双层括号)或通过内部结构之一进行初始化。

更正:大括号的双重级别会避免将输入转换为GLFloats。

最后的细节:未命名的内部结构不是标准的C,做事的标准方法是给内部结构赋予名称,如

typedef union {
    float flts[4];
    struct {
        float r;
        float theta;
        float phi;
        float w;
    } cartesian;
    struct {
        float x;
        float y;
        float z;
        float w;
    } radial;
} FltVector;

FltVector f = {1.0, 2.0, 3.0, 4.0 };

int main(int argc, char * argv[]){
    printf("flts[0]=%f f.radial.r=%f f.cartesian.x=%f\n",
        f.flts[0], f.radial.r, f.cartesian.x);
}

答案 5 :(得分:0)

如前所述,代码使用不同的名称和数据类型分配相同的内存。允许在命名的矢量组件(xyzw)上工作有时会很舒服,同时仍然能够在其他时间将矢量视为数组。

看起来笛卡尔和径向结构的名称是交换的。 “r”,“theta”和“phi”是径向坐标的通用名称,而不是笛卡尔坐标,通常表示为“x”,“y”和“z”。

我认为值得注意的是,使用不同的表示并不严格符合标准(但可能适用于所有现有的C实现),原因有两个:

  1. 读取不是最近编写的联合成员会产生未定义的结果。但是,任何理智的实现都将返回存储在该内存中的值。
  2. 编译器可能会在struct成员之间添加填充(出于性能原因),而数组永远不会填充。但是,在这种情况下,在任何现代CPU上都不太可能发生这种情况。