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;

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

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;
   }

?

任何指针都非常感谢(对不起双关语)

4

6 回答 6

5

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

在这种情况下,联合可能用于提供 1) 结构中相同浮点数的替代名称(例如xr共享相同的内存),以及 2) 访问与数组相同x的四个浮点数(例如,flts[0]共享相同的内存) . 有时联合用于各种“黑客”,通常是不可移植的,以访问某些数据类型的内部,例如机器顺序中的整数中的单个字节。

于 2010-05-20T11:41:07.657 回答
5

如果是sizeof(GLfloat) == sizeof(float)这样,则分配了 4 个浮点数。

flts[0],r并且x都将在这里引用同一块内存。

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

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

于 2010-05-20T11:45:38.020 回答
2

有几个问题:)

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

为什么这是正确的,因为在任何给定时间,联合只拥有一个可能的值。出于这个原因,通常将联合放在结构中,旁边是标识哪个值有效的东西(有时称为有区别的联合scrim)。

一对大括号用于联合,另一对用于数组初始化器。

于 2010-05-20T11:47:17.430 回答
1

为什么使用 FltVector {{}} 时有两组花括号

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

于 2010-05-20T11:57:27.443 回答
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);
}
于 2010-05-20T12:18:09.797 回答
0

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

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

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

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