Aliasing struct and array the conformant way

后端 未结 2 1813
执笔经年
执笔经年 2020-12-11 17:27

In the old days of pre-ISO C, the following code would have surprized nobody:

struct Point {
    double x;
    double y;
    double z;
};
double dist(struct          


        
相关标签:
2条回答
  • 2020-12-11 17:49

    C does not define any way to specify that the compiler must not add padding between the named members of struct Point, but many compilers have an extension that would provide for that. If you use such an extension, or if you're just willing to assume that there will be no padding, then you could use a union with an anonymous inner struct, like so:

    union Point {
        struct {
            double x;
            double y;
            double z;
        };
        double coords[3];
    };
    

    You can then access the coordinates by their individual names or via the coords array:

    double dist(union Point *p1, union Point *p2) {
        double *coord1 = p1->coords;
        double *coord2 = p2->coords;
        double d2 = 0;
    
        for (int i = 0; i < 3; i++) {
            double d = coord2[i]  - coord1[i];
            d2 += d * d;
        }
        return sqrt(d2);
    }
    
    int main(void) {
        // Note: I don't think the inner braces are necessary, but they silence
        //       warnings from gcc 4.8.5:
        union Point p1 = { { .x = .25,  .y = 1,  .z = 3 } };
        union Point p2;
    
        p2.x = 2.25;
        p2.y = -1;
        p2.z = 0;
    
        printf("The distance is %lf\n", dist(&p1, &p2));
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-11 18:05

    This is mainly a complement to JohnBollinger's answer. Anonymous struct members do allow a clean and neat syntax, and C defines a union as a type consisting of a sequence of members whose storage overlap (6.7.2.1 Structure and union specifiers §6). Accessing a member of a union is then specified in 6.5.2.3 Structure and union members:

    3 A postfix expression followed by the . operator and an identifier designates a member of a structure or union object. The value is that of the named member,95) and is an lvalue if the first expression is an lvalue.

    and the (non normative but informative) note 95 precises:

    95) If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be a trap representation.

    That means that for the current version of the standard the aliasing of a struct by an array with the help of anonymous struct member in a union is explicitly defined behaviour.

    0 讨论(0)
提交回复
热议问题