别名结构和数组的统一方式 [英] Aliasing struct and array the conformant way

查看:104
本文介绍了别名结构和数组的统一方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在ISO C之前的年代,以下代码会使人吃惊:

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 Point *p1, struct Point *p2) {
    double d2 = 0;
    double *coord1 = &p1.x;
    double *coord2 = &p2.x;
    int i;
    for (i=0; i<3; i++) {
        double d = coord2[i]  - coord1[i];    // THE problem
        d2 += d * d;
    return sqrt(d2);
}

那时候,我们都知道double对齐允许编译器在struct Point中不添加填充,而我们只是假设指针算术会完成这项工作.

At that time, we all knew that alignment of double allowed the compiler to add no padding in struct Point, and we just assumed that pointer arithmetics would do the job.

不幸的是,这条有问题的行使用了指针算术(p[i]定义为 *(p + i))在任何数组之外,这是标准明确禁止的.用于C11的n1570草案在6.5.6加法运算符§8中说:

Unfortunately, this problematic line uses pointer arithmetics (p[i] being by definition *(p + i)) outside of any array which is explicitely not allowed by the standard. Draft n1570 for C11 says in 6.5.6 additive operators §8:

将具有整数类型的表达式添加到指针指针或从指针指针中减去时, 结果具有指针操作数的类型. 如果指针操作数指向的元素 一个数组对象,并且数组足够大,结果指向一个元素偏移量 原始元素,使得结果和原始的下标之间的差异 数组元素等于整数表达式...

When an expression that has integer type is added to or subtracted from a pointerpointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression...

因为当我们没有相同数组的两个元素时什么也没说,所以它没有被标准以及从那里定义为未定义行为(即使所有常见的编译器对此都感到满意...)

As nothing is said when we have not two elements of the same array, it is unspecified by the standard and from there Undefined Behaviour (even if all common compilers are glad with it...)

问题:

由于该惯用法可以避免代码复制仅将x更改为y然后将z更改,这很容易出错,因此可能是一种一致的方式来浏览结构的元素,就好像它们是该元素的成员一样.相同的数组?

As this idiom allowed to avoid code replication changing just x with y then z which is quite error prone, what could be a conformant way to browse the elements of a struct as if they were members of the same array?

免责声明:显然,它仅适用于相同类型的元素,并且可以通过简单的static_assert检测填充,如我的另一个问题,所以填充,对齐和混合类型不是我的问题.

Disclaimer: It obviously only applies to elements of same type, and padding can be detected with a simple static_assert as shown in that other question of mine, so padding, alignment and mixed types are not my problem here.

推荐答案

C没有定义任何方法来指定编译器不得在struct Point的命名成员之间添加填充,但是许多编译器都有扩展名,可以提供为了那个原因.如果您使用这样的扩展名,或者只是愿意假设没有填充,那么您可以使用带有内部匿名structunion,例如:

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

然后您可以按坐标的个人名称或通过coords数组访问坐标:

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

这篇关于别名结构和数组的统一方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆