-1

Is the following well defined, for different values of REF?

#include <stdio.h>

#define REF 1
#define S 1

int main(void) {
    int a[2][S] = {{1},{2}};
    int *q = REF ? a[1] : 0;
    int *p = a[0] + S;
    memcpy (&q, &p, sizeof q);
    printf ("q[0] = %d\n", q[0]);
    return 0;
}

Note that p points to the after the last element of a[0], not to an element in the array a[0], hence not dereferenceable. But the address stored in p is the address of a[1][0]. p semantically (intentionally?) points "to" (well, out of) a[0] but physically points into a[1].

Can a copy of the bit pattern of a pointer point semantically to an object when the original only physically does?

SEE ALSO

I have asked essentially the same C/C++ question with a different "angle":

Community
  • 1
  • 1
curiousguy
  • 8,038
  • 2
  • 40
  • 58
  • a isn't really an array of arrays, it's an array that has two-dimensional access. The memory in this case will be allocated as one block and will be internally handled as a one-dimensional block. – Sami Kuhmonen Aug 17 '15 at 06:17
  • @SamiKuhmonen So you are saying there is no array bound, as long as I stay inside the one block? So `a[0][1]` is fine? – curiousguy Aug 17 '15 at 06:20
  • I wouldn't say that's fine, since it still is semantically going over, but with a raw pointer you can access the memory consecutively. Trying to find an author stove doc about this allocation – Sami Kuhmonen Aug 17 '15 at 06:23
  • If you point one past an array, there might very well be some other variable there! As the pointer isn't dereferencable, you shouldn't care. – Bo Persson Aug 17 '15 at 07:27
  • @BoPersson here I dereference the one past an array pointer, there is an object there, and my intent is to change it. – curiousguy Aug 17 '15 at 07:36
  • Once you access out-of-bounds, you invoke Undefined Behaviour - doesn't matter *how* you do it. And once you invoke UB, your program ceases to have any meaning or well defined behaviour and you can no longer reason about it or expect *anything*. The only option is to *just not do that*. – Jesper Juhl May 21 '19 at 18:37
  • @JesperJuhl Yes but do I? Does `memcpy (&q, &p, sizeof q)` even changes any memory content? – curiousguy May 21 '19 at 22:18

2 Answers2

4

Given

int blah(int x, int y)
{
  int a[2][5];
  a[1][0] = x;
  a[0][y] = 9;
  return a[1][0];
}

nothing in the Standard would forbid a compiler from recoding that as int blah(int x, int y) { return x; }, nor trapping (or doing anything whatsoever) when y>=5, since a[0] and a[1] are distinct arrays of five elements each. In cases where the last element of an indirectly-accessed structure is a single-element array, compilers have generally included code to allow pointer arithmetic on that array to yield a pointer to storage outside the structure. While such pointer arithmetic would be forbidden by the Standard, it enables useful constructs which could not be practically implemented in any standard-compliant fashion prior to C99.

Note that adding 5 to a[0] would yield an int* that compares identical to a[1], but the fact that a "one-past" pointer compares equal to a pointer which identifes the next object in memory does not imply that it may be safely used to access the latter object. Such accesses may often work, but that doesn't mean compilers are required to have them do so.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • I understand that pointers with equal numerical value can have distinct semantic values, but I copy the numerical value with `memcpy`. Is `memcpy` magic? Can it transfer the semantic value? – curiousguy Aug 18 '15 at 21:08
  • 2
    @curiousguy: Modern compiler theory seems to suggest that compilers are free to have `memcpy` or `memmove` bring along a pointer's provenance or not as they see fit. The only kind of "scrubbing" I know of that memcpy is required to perform is to resolve any strict-aliasing issues with regard to the content copied. Given `void *p=malloc(sizeof (long)); long *lp=p; short *sp=p; *lp=1234; memmove(sp,lp,sizeof(short)); printf("%d",*sp);` the `memmove` would make the access to `*sp` well-defined. Without `memmove` it would be Undefined Behavior. Note that `memcpy` would yield UB directly. – supercat Aug 18 '15 at 23:24
1

Can a copy of the bit pattern of a pointer point semantically to an object when the original only physically does?

There is no such distinction effectively, because a[0] + S is the same as a[1], assuming that inner array is declared with S size.

The following:

int a[2][S];

declares two-elements array, where each element is an array of S-elements of type int. Arrays are stored contigously and there is no padding before/between/after its elements.

We will prove, that a[0] + S == a[1] holds. It can be rewritten as:

*(a + 0) + S == *(a + 1)

By pointer arithmetic, RHS adds 1 * sizeof(*a) bytes to a, that is the same as size of the inner array. LHS is little more complex, as addition is performed after dereference of a, thus it adds:

S * sizeof(**a) bytes,

Both sides are guaranteed to be equal when they point to the same object (the same memory location), of the same type. Hence you could rewrite it into "absolute" one-byte form as:

(char *)a + S * sizeof(**a) == (char *)a + sizeof(*a)

This reduces into:

S * sizeof(**a) == sizeof(*a)

We know, that sub-array *a has S elements of type of **a (i.e. int), so both offsets are the same. Q.E.D.

Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137