Problem with "restrict"

  • Thread starter diegotorquemada
  • Start date
T

Tim Rentsch

christian.bau said:
a, b, and c all have the type int*, and therefore must all be
correctly aligned for an int. Where do unaligned pointers
enter into this?

For unaligned pointers the assumption that an assignment *a = *c
cannot change the value of *c is wrong. Therefore you need to
make some argument why *c only needs to be read once. And on many
implementations int* at arbitrary byte locations are correctly
aligned for an int. Therefore the bytes of *a and *c can
partially overlap. [snip example]

This argument is wrong, because of 6.5.16.1 p3. Partial overlap
in such cases is specifically undefined behavior. Therefore
the assumption that *a = *c won't affect the value of *c is
a priori conforming and needs no further justification.
 
T

Tim Rentsch

christian.bau said:
This argument is wrong, because of 6.5.16.1 p3. Partial overlap
in such cases is specifically undefined behavior. Therefore
the assumption that *a = *c won't affect the value of *c is
a priori conforming and needs no further justification.

You just gave exactly the further justification that you claim isn't
needed.

void f (int* p, int* q)
{
char tmp1 [sizeof (int)];
char tmp2 [sizeof (int)];

*p = 1;
memcpy (tmp1, p, sizeof (int));
*q = 2;
memcpy (tmp2, p, sizeof (int));

if (memcmp (tmp1, tmp2, sizeof (int)) != 0)
printf ("Can this happen?\n");
}
[indentation added]

The printf can happen on some implementations without any undefined
behaviour involved.

This example is irrelevant to the point under discussion. Do you
not understand the difference between

*q = 2;

and

*q = *p;

? Of course it is possible that the first of these assignments
can change the value of *p (in the context of the code sample,
and stipulating no undefined behavior). The second cannot.
 
G

glen herrmannsfeldt

(snip, someone wrote)
(snip)
You are of course wrong. On an implementation where the type "int" has
no alignment restriction, I can write
char myarray [sizeof (int) + 1];
int* p = (int *) &myarray [0];
int* q = (int *) &myarray [1];
*p = 1;
*q = *p;
On a common implementation where sizeof (int) == 4, the first
assignment sets the bytes in myarray to

The question isn't that you can do that, but what does the C
standard say about doing it?
1, 0, 0, 0, unknown (littleendian) or 0, 0, 0, 1, unknown
(bigendian).
The second assignment sets the bytes to
1, 1, 0, 0, 0 (littleendian) or 0, 0, 0, 0, 1 (bigendian).
In either case the second assignment modifies the four bytes that p
points to. Without any undefined behaviour up to this point.

If the C standard says that it is undefined, then it is undefined,
even if your compiler happens to do what you thing it should do.

-- glen
 
N

Noob

Philip said:
Read 6.5.16.1p3, as he suggested.

For the interested reader, C99 6.5.16.1p3 states:
If the value being stored in an object is read from another object
that overlaps in any way the storage of the first object, then the
overlap shall be exact and the two objects shall have qualified or
unqualified versions of a compatible type; otherwise, the behavior
is undefined.

Regards.
 
T

Tim Rentsch

christian.bau said:
christian.bau said:
On Mar 16, 3:51 am, Tim Rentsch <[email protected]> wrote:
This argument is wrong, because of 6.5.16.1 p3. Partial overlap
in such cases is specifically undefined behavior. Therefore
the assumption that *a = *c won't affect the value of *c is
a priori conforming and needs no further justification.
You just gave exactly the further justification that you claim isn't
needed.
void f (int* p, int* q)
{
char tmp1 [sizeof (int)];
char tmp2 [sizeof (int)];
*p = 1;
memcpy (tmp1, p, sizeof (int));
*q = 2;
memcpy (tmp2, p, sizeof (int));
if (memcmp (tmp1, tmp2, sizeof (int)) != 0)
printf ("Can this happen?\n");
}
[indentation added]
The printf can happen on some implementations without any undefined
behaviour involved.

This example is irrelevant to the point under discussion. Do you
not understand the difference between

*q = 2;

and

*q = *p;

? Of course it is possible that the first of these assignments
can change the value of *p (in the context of the code sample,
and stipulating no undefined behavior). The second cannot.

You are of course wrong. On an implementation where the type "int" has
no alignment restriction, I can write

char myarray [sizeof (int) + 1];
int* p = (int *) &myarray [0];
int* q = (int *) &myarray [1];
*p = 1;
*q = *p;

On a common implementation where sizeof (int) == 4, the first
assignment sets the bytes in myarray to

1, 0, 0, 0, unknown (littleendian) or 0, 0, 0, 1, unknown
(bigendian).

The second assignment sets the bytes to

1, 1, 0, 0, 0 (littleendian) or 0, 0, 0, 0, 1 (bigendian).

In either case the second assignment modifies the four bytes that p
points to. Without any undefined behaviour up to this point.

As comments from Philip Lantz and Noob have explained, the second
assignment has undefined behavior, because of the rule about no
partial overlap in assignments.

Also, not that this matters, both assignment statements result in
undefined behavior because of effective type rules. The type of
elements in 'myarray' is 'char'. The effective type rules allow
an object whose effective type is 'int' to be accessed using an
lvalue of type 'char' (or any other character type); they do not
allow an object whose effective type is 'char' to be accessed
using an lvalue of type 'int'.

The problem with effective types can be worked around by using
allocated storage instead a declared character array. However,
there remains the problem with undefined behavior because of
the partial-overlap assignment, which is what I've been saying
all along.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,077
Messages
2,570,566
Members
47,202
Latest member
misc.

Latest Threads

Top