Re: C99 clarification on pointers to aggregate object and its sub objects



On 01/10/2012 11:29 AM, Wojtek Lerch wrote:
On 10/01/2012 7:27 AM, James Kuyper wrote:
On 01/10/2012 01:59 AM, ty ty wrote:
Given that sizeof(int) == 4, and the declaration:
int a[3][4];
int *p =& a[0][0];
int (*q)[4] =&a [0];
int (*r)[3][4] =&a;
...

b) Is (char *)p:
>> i) a pointer to the first byte of the integer object a[0][0] or
>> ii) a pointer to the first byte of the 1 dimensional array a [0] or
>> iii) a pointer to the first byte of the 2 dimensional array a or
>> iv) all of the above ?
>
> iv.

Right; they're all the same byte. The tricky question is how many times
you can increment the pointer before the behaviour becomes undefined.

If you take the standard's words literally, p points to an object of
type int. The size of that object is four. Therefore adding five to
(char*)p is undefined behaviour.

More accurately, that object has the size sizeof(int), which could be
any positive integer, though 4 is one of most popular options nowadays.

Pointers to character type have a special exemption from those rules,
though it's tricky to prove that.. p points at a, a[0], and a[0][0]. All
of those are objects, and according to 6.2.6.1p4, any of those objects
can be copied into an array of unsigned char with a length equal to the
size of the object (for example, by using memcpy()). The resulting set
of bytes constitutes the object representation of that value. 6.5p7 says
that an object with a given type and value can be copied, either using
memcpy or as an array of character type, into memory with no declared
type, and as a result produce an object whose effective type and value
are the same as the source object.

The fact that, in both clauses, the standard gives memcpy() as an
example of how this can be done, rather than specifying that memcpy() is
the only way to do it, implies that this is not a magic feature of
memcpy(). A user-defined function with the same interface as memcpy(),
which implements the same behavior defined for memcpy(), but which has a
different name, could be used as well. That, in turn, implies that
entirety of any object's representation may be accessed by using through
a pointer to a character type

That's a very round-about way of reaching such a conclusion; I'd prefer
it if the standard said these things more directly. I consider such an
argument acceptable only because it confirms what we all "know" to be
true, despite the fact that the standard fails to say it more clearly.

c) Following (b), do any of these lead to undefined behaviour?
i) memset ((char*)p, 0, sizeof (*p));
ii) memset ((char*)p, 0, sizeof (*q));
iii) memset ((char*)p, 0, sizeof (*r));

memset()'s first parameter is of type void*, rendering the casts
unnecessary. With or without the casts, none of those function calls has
undefined behavior.

I don't think that's entirely clear. If adding five to (char*)p is
undefined behaviour, then ii and iii are both undefined, aren't they?

Disagreeing with you about the undefined behavior of
1+sizeof(int)+(char*)p necessarily implies that I disagree with you
about ii and iii.

d) Since an array in an expression is converted to a pointer to its
1st element, and&a[0][0] points to an object of integer size, are
these really valid:
i) memset (a, 0, sizeof (a));
ii) memset (&a[0][0], 0, sizeof (a));
or we can only do this:
iii) memset (&a, 0, sizeof (a));

All three have the same well-defined behavior, which makes 'i' the
preferred form.

Again, I don't think that's entirely clear from the words of the
standard, even though it probably is the intent.

All of your concerns would be more relevant if char* were replace with
int*, and memset() were replaced with a function like intset(), defined
below:

void intset(int *s, int c, size_t n)
{
while(n--)
*s++ = c;
}

intset(a[0], 0, 5) would indeed have undefined behavior (the 5 here is
one more than the length of the second dimension of 'a'; it has nothing
to do with the 5 that you were mentioning earlier).
.



Relevant Pages

  • Re: C99 clarification on pointers to aggregate object and its sub objects
    ... a pointer to the first byte of the 1 dimensional array a or ... That expression is then converted to an expression with type 'int *'. ... 'p' _also_ points to an element of an array object with 'sizeof *p' elements of type 'char'. ... memset p, 0, sizeof ); ...
    (comp.std.c)
  • Re: Pointer dereference rather than sizeof?
    ... operator as an argument to malloc calls. ... if said pointer is undefined. ... you undefined behaviour - which, presumably, you don't want. ... sizeof DOES NOT EVALUATE ITS OPERAND (except in one weird case in C99 ...
    (comp.lang.c)
  • Re: C99 clarification on pointers to aggregate object and its sub objects
    ... The tricky question is how many times you can increment the pointer before the behaviour becomes undefined. ... Therefore adding five to p is undefined behaviour. ... memset p, 0, sizeof ); ...
    (comp.std.c)
  • Re: end of array
    ... You can make a pointer point to anything. ... arithmetic invokes undefined behaviour and anything can happen. ... I will probably get a segmentation fault or a memory fault. ... Just calculating a pointer like that can cause UB? ...
    (comp.lang.c)
  • Re: system() without waiting
    ... Okay, "results in" undefined behaviour, then. ... In SUSv3 the execlpfunction has a prototype that ends with ", ... null pointer is a pointer that results from conversion of a null pointer ... null-terminated character strings. ...
    (comp.unix.programmer)