多维数组的别名 [英] Aliasing of multi-dimensional arrays

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

问题描述

众所周知,二维数组是数组的数组,标准要求它是连续分配的非空对象集(6.2.5类型§20)-对象在这里是一维数组.

众所周知,对于所有常见实现,对于T arr2d[X][Y],以下等式都是成立的,其中T是类型,X和Y为整数常数.

(char *) &arr2d[i][j] == (char *) &arr2d[0][0] + i * Y * sizeof(T) + j * sizeof(T)

上面的代码让我们可以允许别名一个2D数组和一个相同大小的1D数组,甚至另一个总大小相同的2D数组:

例如,以下程序在没有警告的情况下编译并运行,并给出预期的输出:

#include <stdio.h>

int main() {
    int i, j, k=0;
    int arr2d[3][4];   // array of 3 array of 4 ints
    int *arr1 = &arr2d[0][0];  // pointer to first element of an array of 12 ints (1)
    int (*arrx)[3] = (int(*)[3]) arr1; //pointer to first row of an array of arrays of 3 ints
                                       //(2)

    for (i=0; i<12; i++) arr1[i] = k++; // (3)

    for (i=0; i<3; i++) {
        for (j=0; j<4; j++) {
            printf("%3d", arr2d[i][j]);
        }
        putc('\n', stdout);
    }
    for (i=0; i<4; i++) {
        for (j=0; j<3; j++) {
            printf("%3d", arrx[i][j]); 
        }
        putc('\n', stdout);
    }
    return 0;
}

但是:

  • 在(1)和(3)行中将别名3d4的2D数组换成1D数组12
  • 第(2)行别名将2D数组3x4转换为2D数组4x3(通过指向int的指针)

我的问题是:

  • 根据C标准,(1)和(3)是否有效?
  • 如果是,(2)是否有效?

解决方案

即使严格的别名规则允许从包含该对象的对象访问一种类型的对象,标准中也有两个元素可以说是对2D数组进行别名不允许使用相同大小的一维数组:

兼容类型

6.2.7兼容类型和复合类型

1如果两个类型相同,则它们具有兼容类型.
...
3可以从两种兼容的类型构造复合类型.这是一种 与这两种类型都兼容,并且满足以下条件:

  • 如果一种类型是已知常量大小的数组,则复合类型是该类型的数组 大小;否则,如果一种类型是可变长度数组,则复合类型就是该类型.
    ...

这些规则递归地应用于这两种类型的派生类型.

符合性:

4符合性

...

  1. ...本国际标准中另有未定义的行为表示 通过未定义的行为"一词或通过省略任何明确定义的标准 行为.这三者之间的重点没有差异.他们都描述 未定义的行为" .
  2. 在所有其他方面都正确的程序,对正确的数据进行操作,其中包含 未指明的行为应是正确的程序,并应按照5.1.2.3进行操作.
    ...
  3. 严格遵守的程序应仅使用语言和库的那些功能 2)它不应产生依赖于任何 未指定,未定义或实现定义的行为,并且不得超过任何 最低实施限制.

我的理解是,根据标准,未指定是2D数组与1D数组的混叠,因此会导致不确定的行为.使用它的程序仍然是正确的程序,应能成功编译,但其输出未指定

严格符合标准的程序不应将2D数组别名为1D数组.

话虽这么说,为了不破坏严重依赖它的遗留代码,通用实现允许它并按预期对其进行处理(按未定义的行为允许). >

It is well known that a 2D array is an array of arrays, and that it is required by standard to be a contiguously allocated nonempty set of objects (6.2.5 Types §20) - object being a 1D array here.

It is also well known that for all common implementations the following equality is true for T arr2d[X][Y] where T is a type and X and Y integral constants:

(char *) &arr2d[i][j] == (char *) &arr2d[0][0] + i * Y * sizeof(T) + j * sizeof(T)

The above let think that it could be allowed to alias a 2D array and an 1D array of same size, or even another 2D array of same total size:

For example the following program compiles and runs with no warnings, and gives expected output:

#include <stdio.h>

int main() {
    int i, j, k=0;
    int arr2d[3][4];   // array of 3 array of 4 ints
    int *arr1 = &arr2d[0][0];  // pointer to first element of an array of 12 ints (1)
    int (*arrx)[3] = (int(*)[3]) arr1; //pointer to first row of an array of arrays of 3 ints
                                       //(2)

    for (i=0; i<12; i++) arr1[i] = k++; // (3)

    for (i=0; i<3; i++) {
        for (j=0; j<4; j++) {
            printf("%3d", arr2d[i][j]);
        }
        putc('\n', stdout);
    }
    for (i=0; i<4; i++) {
        for (j=0; j<3; j++) {
            printf("%3d", arrx[i][j]); 
        }
        putc('\n', stdout);
    }
    return 0;
}

But:

  • line (1) and (3) alias a 2D array 3x4 to a 1D array 12
  • line (2) alias a 2D array 3x4 to a 2D array 4x3 (via a pointer to int)

My questions are:

  • are (1) and (3) valid according to the C standard?
  • if yes, is (2) valid?

解决方案

Even if the strict aliasing rules allows to access an object of one type from an object containing it, there are two elements in standards to say that aliasing a 2D array to a 1D array of same size is not allowed:

Compatible type

6.2.7 Compatible type and composite type

1 Two types have compatible type if their types are the same.
...
3 A composite type can be constructed from two types that are compatible; it is a type that is compatible with both of the two types and satisfies the following conditions:

  • If one type is an array of known constant size, the composite type is an array of that size; otherwise, if one type is a variable length array, the composite type is that type.
    ...

These rules apply recursively to the types from which the two types are derived.

Conformance:

4 Conformance

...

  1. ... Undefined behavior is otherwise indicated in this International Standard by the words ‘‘undefined behavior’’ or by the omission of any explicit definition of behavior. There is no difference in emphasis among these three; they all describe ‘‘behavior that is undefined’’.
  2. A program that is correct in all other aspects, operating on correct data, containing unspecified behavior shall be a correct program and act in accordance with 5.1.2.3.
    ...
  3. A strictly conforming program shall use only those features of the language and library specified in this International Standard.2) It shall not produce output dependent on any unspecified, undefined, or implementation-defined behavior, and shall not exceed any minimum implementation limit.

My understanding is that aliasing of 2D array with a 1D array is unspecified by the standard and as such leads to undefined behaviour. A program using it is still a correct program that shall be successfuly compiled, but its output is unspecified

A stricly conforming program should not alias a 2D array to an 1D array.

That being said, common implementation allows it and process it as expected (which is allowed per undefined behaviour...) in order to not break legacy code that heavily depends on it.

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

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