别名结构和数组是否合法? [英] Is it legal to alias a struct and an array?

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

问题描述

结构中相同类型的连续成员之间的指针算术曾经是一种常见的做法,而指针算术仅在数组内部有效.在C ++中,这显然是未定义行为,因为只能通过声明或新表达式创建数组.但是C语言将数组定义为连续分配的非空对象集,其中包含 特殊的成员对象类型,称为元素类型.(n1570草案,适用于C11,6.2.5类型§20).因此,只要我们可以确保成员是连续的(意味着它们之间没有填充),将其视为数组是合法的.

Pointer arithmetics between consecutive members of same type in a struct used to be a common practice while pointer arithmetics is only valid inside an array. In C++ it would be explicitely Undefined Behaviour because an array can only be created by a declaration or a new expression. But C language defines an array as a contiguously allocated nonempty set of objects with a particular member object type, called the element type. (n1570 draft for C11, 6.2.5 types §20). So provided we can make sure that that the members are consecutive (meaning no padding between them) it could be legal to see that as an array.

这是一个简化的示例,可以在不发出警告的情况下进行编译,并在运行时给出预期的结果:

Here is a simplified example, that compiles without a warning and gives expected results at run time:

#include <stdio.h>
#include <stddef.h>
#include <assert.h>

struct quad {
    int x;
    int y;
    int z;
    int t;
};

int main() {
    // ensure members are consecutive (note 1)
    static_assert(offsetof(struct quad, t) == 3 * sizeof(int),
        "unexpected padding in quad struct");
    struct quad q;
    int *ix = &q.x;
    for(int i=0; i<4; i++) {
        ix[i] = i;
    }
    printf("Quad: %d %d %d %d\n", q.x, q.y, q.z, q.t);
    return 0;
}

在这里并没有什么意义,但是我已经看到了一个真实的示例,其中在结构成员之间进行迭代可以使代码更简单,而出现错字的风险也较小.

It does not really make sense here, but I have already seen real world example where iterating among members of a struct allows simpler code with less risk of typo.

问题:

在上面的示例中,static_assert是否足以使结构的别名具有数组合法性?

In the above example, is the static_assert enough to make legal the aliasing of the struct with an array?

(注1)由于结构描述了按顺序分配的成员对象的非空集,因此以后的成员必须具有递增的地址.简单地,编译器可以在它们之间包括填充.因此,如果最后一个成员(此处为t)的偏移量是sizeof(int)的3倍加上其前的总填充,则该偏移量.如果偏移量恰好是3 * sizeof(int),则struct中没有填充

(note 1) As a struct describes a sequentially allocated nonempty set of member objects, later members must have increasing addresses. Simply the compiler could include padding between them. So the offset of last member (here t) if 3 times sizeof(int) plus the total padding before it. If the offset is exactly 3 * sizeof(int) then there is no padding in struct

重复提出的问题既包含一个公认的答案,可以认为它是UB,又包含一个 +1答案认为这是合法的,因为我可以确保不存在填充

The question proposed as a duplicate contains both an accepted answer that let think that it would be UB, and a +1 answer that let think that it could be legal because I could ensure that no padding could exist

推荐答案

我要争辩UB.首先, 6.5.6加法运算符中的强制性引号:

I'm gonna argue UB. First and foremost, the mandatory quote from 6.5.6 Additive operators:

将具有整数类型的表达式添加或减去时 从指针开始,结果具有指针操作数的类型.如果 指针操作数指向数组对象的元素,该数组 足够大,结果指向的元素与 原始元素,使得下标的差异 结果数组元素和原始数组元素等于整数表达式. 换句话说,如果表达式P指向 数组对象,表达式为(P)+ N(相当于N +(P))和(P)-N (其中N的值为n)分别指向第i + n个和 数组对象的第i-n个元素(如果存在).而且,如果 表达式P指向数组对象的最后一个元素,即 表达式(P)+1指向数组对象的最后一个元素, 并且如果表达式Q指向数组的最后一个元素之后的一个 对象,表达式(Q)-1指向数组的最后一个元素 目的.如果指针操作数和结果都指向元素 相同 array对象的元素,或者在 array的最后一个元素之后 对象,评估不会产生溢出;否则, 行为是不确定的.如果结果指向最后一个元素 数组对象的形式,不得将其用作一元*的操作数 被评估的运算符.

When an expression that has integer type is added to or subtracted from a pointer, 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. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i-n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.

我强调了我认为这件事的症结所在.当您说数组对象是具有特定成员对象类型(称为元素类型)的连续分配的非空对象集"时,您说对了..但是相反是真的吗?连续分配的对象集是否构成数组对象?

I emphasized what I consider the crux of the matter. You are right when you say that an array object is "a contiguously allocated nonempty set of objects with a particular member object type, called the element type". But is the converse true? Does a consecutively allocated set of objects constitute an array object?

我要说不.需要显式创建对象.

I'm going to say no. Objects need to be explicitly created.

因此,在您的示例中,没有数组对象.通常,有两种方法可以在C中创建对象.以自动,静态或线程本地持续时间声明它们.或分配它们并为存储提供有效的类型.您都没有创建数组.这使得算术在形式上是不确定的.

So for your example, there is no array object. There are generally two ways to create objects in C. Declare them with automatic, static or thread local duration. Or allocate them and give the storage an effective type. You did neither to create an array. That makes the arithmetic officially undefined.

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

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