寻求 C Union 的明确性

发布于 2024-09-02 09:23:49 字数 700 浏览 3 评论 0原文

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

非常感谢任何指点(抱歉双关语)

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

Ok, so i think i get how to use this, (or, this is how i have seen it used) ie.

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

But i'm not really groking how much storage has been declared by the union (4 floats? 8 floats? 12 floats?), how? and why? Also why two sets of curly braces when using FltVector {{}}?

Why use a union at all? Why not do..

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

?

Any pointers much appreciated (sorry for the pun)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

幸福还没到 2024-09-09 09:23:49

如果 sizeof(GLfloat) == sizeof(float) 则已分配 4 个浮点数。

flts[0]rx 在这里都引用同一块内存。

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

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

if sizeof(GLfloat) == sizeof(float) then, 4 floats have been allocated.

flts[0], r and x will all refer to the same piece of memory here.

In a union, every different variable declared in the union refers to the same piece of memory.

Here we have 3 variables, 2 structs and an array, and each of them start at the same point in memory.

姜生凉生 2024-09-09 09:23:49

联合允许您为不同类型的变量“回收”同一内存区域。一般来说,联合占用的存储空间与其最大的单个成员一样多,在本例中可能是 4 个浮点数。您可以使用sizeof进行检查。

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

A union allows you to “recycle” the same area of memory for different types of variables. Generally the union takes as much storage as its single largest member, in this case probably 4 floats. You can check with sizeof.

In this case the union is probably used to provide 1) alternative names for the same floats in the struct (e.g. x and r share the same memory), and 2) access to the same four floats as an array (e.g. x and flts[0] share the same memory). Sometimes unions are used in various “hacks”, usually non-portable, to access the internals of some data type e.g. the individual bytes in an integer in the machine order.

若无相欠,怎会相见 2024-09-09 09:23:49

有几个问题:)

@Arkku 关于尺寸的说法是正确的。对齐也可以发挥作用,但可能不是在这里。

为什么这是真的,因为在任何给定时间,并集仅保留可能值之一。出于这个原因,通常将联合放在一个结构中,旁边放置一些标识哪个值有效的东西(有时称为可区分联合scrim)。

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

A few questions there :)

@Arkku is right about the size. Alignment can also play a part, but probably not here.

Why this is true is that at any given time the union only holds one of the possible values. For this reason it's common to have the union in a struct alongside something which identifies which value is valid (sometimes called a discriminated union or scrim).

One pair of braces is for the union, and the other for the array initalizer.

如日中天 2024-09-09 09:23:49

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

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

why two sets of curly braces when using FltVector {{}}

Look at the whole line, FltVector fltVec1 = {{1.0f, 1.0f, 1.0f, 1.0f}};
You're initializing the four floats in the first struct in the union. As you can see from the bold "in"s, there are two levels of nesting. If the level of nesting was even deeper, you could even have more curly braces.

云胡 2024-09-09 09:23:49

在您的示例中,如果我们考虑变量的名称,则联合肯定不会用于通过 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);
}

In your example, if we consider the name of the variables, the union is most certainly not used to access the same memory cell through say x and r (as a radius and an x coordinate would not fit well), but to leave user provide the same argument for both. It's much simpler to set x, y, z, w when you use cartesian coordinates and would be awkward to use these same names for radial coordinates. And both are simpler than just array indices. You probably also have another parameter around that give the type of the provided coordinate (either cartesian or radial). Thus you will have a discriminated union as pdbartlett calls them.

In this case the double level of braces is useless as the array can be initialized either through the array (double level of braces) or through one of the inner struct.

correction: the double level of braces avoid casting inputs to GLFloats.

Last detail: unnamed inner structs is not standard C, the standard way to do things is to give names to inner structs like in

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);
}
揽清风入怀 2024-09-09 09:23:49

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

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

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

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

As have been noted, the code allocates the same memory using different names and datatypes. It can some times be comfortable to be allowed to work on named vector-components (xyzw), while still being able to treat the vector as an array at other times.

It looks like the names for the cartesian and the radial structs are swapped, though. "r", "theta" and "phi" are common names for radial coordinates, not cartesian ones which are usually denoted as "x", "y" and "z".

I think it's worth noting that using the different representations is not strictly standard-compliant (but probably works fine on all existing C-implementations), for two reasons:

  1. Reading a union member that is not the most recently written yields undefined result. Any sane implementation will return the value stored in that memory, though.
  2. The compiler might add padding between struct members(for performance reasons), while arrays are never padded. This is unlikely to happen in this case on any modern CPU, though.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文