代码之家  ›  专栏  ›  技术社区  ›  hooleyhoop

寻求C工会的明确性

  •  5
  • hooleyhoop  · 技术社区  · 15 年前
    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 回复  |  直到 13 年前
        1
  •  5
  •   Salgar    15 年前

    如果 sizeof(GLfloat) == sizeof(float)

    flts[0] , r x 都是指同一段记忆。

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

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

        2
  •  5
  •   Arkku    15 年前

    sizeof .

    x r 相同的 四个浮点数作为一个数组(例如。 flts[0] 共享相同的内存)。有时在各种黑客中使用联合,通常是不可移植的,以访问某些数据类型的内部,例如机器顺序中整数中的单个字节。

        3
  •  2
  •   pdbartlett    15 年前

    @Arkku的尺寸是对的。对齐也可以发挥作用,但可能不是在这里。

    为什么这是真的是在任何给定的时间工会只持有一个可能的价值观。由于这个原因,结构中的并集通常与标识哪个值有效(有时称为 歧视性结合 ).

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

        4
  •  1
  •   MSalters    15 年前

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

    FltVector fltVec1 = {{1.0f, 1.0f, 1.0f, 1.0f}}; 你正在初始化四个浮动 在里面 在里面 工会。从粗体“in”可以看出,嵌套有两个级别。如果嵌套的层次更深,你甚至可以有更多的花括号。

        5
  •  1
  •   kriss    15 年前

    在您的示例中,如果我们考虑变量的名称,那么union肯定不是用来通过x和r访问同一个存储单元的(因为半径和x坐标不太合适),而是让用户为两者提供相同的参数。当你使用笛卡尔坐标时,设置x,y,z,w要简单得多,如果用这些相同的名字来表示径向坐标的话会很尴尬。两者都比数组索引简单。您可能还有另一个参数,它给出了所提供坐标的类型(笛卡尔坐标或径向坐标)。因此,你将拥有一个被歧视的联盟,正如巴特利特所说的那样。

    :双层大括号避免将输入强制转换为glfloat。

    最后一个细节:未命名的内部结构不是标准的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);
    }
    
        6
  •  0
  •   kusma    15 年前

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

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

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

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