Multidimensional array indexing using pointer to elements

前端 未结 3 1360
无人共我
无人共我 2020-12-11 01:17

As far as I know, multidimensional array on stack will occupy continuous memory in row order. Is it undefined behavior to index multidimensional array using a pointer to ele

3条回答
  •  春和景丽
    2020-12-11 01:49

    The problem here is the strict aliasing rule that exists in my draft n3337 for C++11 in 3.10 Lvalues and rvalues [basic.lval] § 10. This is an exhaustive list that does not explicetely allow to alias a multidimensional array to an unidimensional one of the whole size.

    So even if it is indeed required that arrays are allocated consecutively in memory, which proves that the size of a multidimensional array, say for example T arr[n][m] is the product of is dimensions by the size of an element: n * m *sizeof(T). When converted to char pointers, you can even do arithmetic pointer operations on the whole array, because any pointer to an object can be converted to a char pointer, and that char pointer can be used to access the consecutive bytes of the object (*).

    But unfortunately, for any other type, the standard only allow arithmetic pointer operations inside one array (and by definition dereferening an array element is the same as dereferencing a pointer after pointer arithmetics: a[i] is *(a + i)). So if you both respect the rule on pointer arithmetics and the strict aliasing rule, the global indexing of a multi-dimensional array is not defined by C++11 standard, unless you go through char pointer arithmetics:

    int a[3][4];
    int *p = &a[0][0]; // perfectly defined
    int b = p[3];      // ok you are in same row which means in same array
    b = p[5];          // OUPS: you dereference past the declared array that builds first row
    
    char *cq = (((char *) p) + 5 * sizeof(int)); // ok: char pointer arithmetics inside an object
    int *q = (int *) cq; // ok because what lies there is an int object
    b = *q;            // almost the same as p[5] but behaviour is defined
    

    That char pointer arithmetics along with the fear of breaking a lot of existing code explains why all well known compiler silently accept the aliasing of a multi-dimensional array with a 1D one of same global size (it leads to same internal code), but technically, the global pointer arithmetics is only valid for char pointers.


    (*) The standard declares in 1.7 The C++ memory model [intro.memory] that

    The fundamental storage unit in the C++ memory model is the byte... The memory available to a C++ program consists of one or more sequences of contiguous bytes. Every byte has a unique address.

    and later in 3.9 Types [basic.types] §2

    For any object (other than a base-class subobject) of trivially copyable type T, whether or not the object holds a valid value of type T, the underlying bytes making up the object can be copied into an array of char or unsigned char.

    and to copy them you must access them through a char * or unsigned char *

提交回复
热议问题