2010-05-20 63 views
5
typedef union { 
    float flts[4]; 
    struct { 
     GLfloat r; 
     GLfloat theta; 
     GLfloat phi; 
     GLfloat w; 
    }; 
    struct { 
     GLfloat x; 
     GLfloat y; 
     GLfloat z; 
     GLfloat w; 
    }; 
} FltVector; 

好的,所以我想我得到如何使用这个,(或者,这是我如何看到它使用)ie。寻求C Union清晰度

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

但我真的不groking多少存储已经由工会宣布(4辆花车?8辆花车?12个浮点?),怎么样?为什么?另外为什么两套花括号使用FltVector {{}}?

为什么要使用联合?为什么不这样做..

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

任何指针赞赏(抱歉的双关语)

回答

5

if if sizeof(GLfloat) == sizeof(float) then,4 floats has been allocated。

flts[0]rx这里都是指同一块内存。

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

这里我们有3个变量,2个结构体和一个数组,每个都在内存中的相同位置开始。

5

一个工会,您可以“回收”同样的内存用于不同类型的变量区域。通常情况下,工会需要尽可能多的存储,因为它可能只有4个浮动。你可以用sizeof查询。

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

+0

这就是在这种情况下:4浮点数(如果GLfloat等于浮点数) – tur1ng 2010-05-20 11:42:21

2

有几个问题:)

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

为什么这是真的,在任何给定的时间,联盟只有一个可能的值。由于这个原因,通常在一个结构中存在一个标识哪个值有效的联合(有时称为歧视联盟scrim)。

一对大括号用于联合,另一个用于数组initalizer。

1

为什么两套大括号的使用FltVector时,{{}}

看整条生产线,FltVector fltVec1 = {{1.0f, 1.0f, 1.0f, 1.0f}}; 你初始化四个浮点第一结构的联盟。正如你从粗体的“in”中看到的那样,有两层嵌套。如果嵌套层次更深,你甚至可以拥有更多的花括号。

+0

是的,但是这里我们可以不加删除一组大括号,因为它会初始化第一个内部结构。 – kriss 2010-05-20 12:22:02

1

在你的例子中,如果我们考虑变量的名字,union肯定不是用来通过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); 
} 
+0

感谢大家的帮助,现在真的很清楚了。 – hooleyhoop 2010-05-20 14:27:27

+0

这不是“更平常”,它实际上是语言所必需的。它由于非标准的编译器扩展而编译时没有这些名称。 – AnT 2010-05-22 01:15:01

+0

@AndreyT:我会编辑答案,我没有检查标准(无论如何,我不是一个真正的标准信徒,并且把编译器当成真正的东西。在我眼中,stndard只是避免太多熵的工具,引导语言进化)。 – kriss 2010-05-22 08:36:58

0

正如人们已经注意到,在代码中使用不同的分配相同的内存名称和数据类型。它有时可以被允许处理命名向量组件(xyzw),同时仍然可以将向量作为一个数组在其他时间处理。

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

我认为这是值得注意的是,使用不同的表示方法不严格符合标准的(但可能工作正常,所有现有的C-实现),有两个原因:

  1. 阅读工会成员不是最近写入的结果为未定义结果。不过,任何理智的实现都会返回存储在内存中的值。
  2. 编译器可能会在结构成员之间添加填充(出于性能原因),而数组从不填充。不过,这种情况在任何现代CPU上都不太可能发生。