Is pointer arithmetic associative?

F

Francois Grieu

Are these programs correct ?

#include <stdio.h>
unsigned char a[2] = {1,2};
int main(void) {
unsigned char j;
for(j=1; j<=2; ++j)
printf("%u\n", *( a+j-1 ));
return 0; }


#include <stdio.h>
unsigned char a[2] = {1,2};
int main(void) {
unsigned char j;
for(j=1; j<=2; ++j)
printf("%u\n", *( a-1+j ));
return 0; }


#include <stdio.h>
unsigned char a[2] = {1,2};
int main(void) {
unsigned char j;
for(j=1; j<=2; ++j)
printf("%u\n", *( a+(j-1) ));
return 0; }

rot-13 spoiler: bayl gur ynfg bar vf pbeerpg.


One compiler I use generates correct and tight code for the
second form; but it fails for *(-1+a+j) [not due to an
architectural restriction, but due to a plain compiler bug].

Isn't it a shame C programming is so complex ? Given that on
most platforms, pointer arithmetic is associative, and so many
programs out there assume it blindly, is not it time for a
future C standard to waive these restrictions on pointer
associativity in at least a branch of the standard, say with
a predefined constant __ASSOCIATIVE_POINTERS__ ?


Francois Grieu
[reposted with fixed spoiler !]
 
M

Marc Boyer

Francois Grieu said:
Isn't it a shame C programming is so complex ?

Yes it is, but is there a better solution ?
Given that on
most platforms, pointer arithmetic is associative, and so many
programs out there assume it blindly, is not it time for a
future C standard to waive these restrictions on pointer
associativity in at least a branch of the standard, say with
a predefined constant __ASSOCIATIVE_POINTERS__ ?

Did you thought to all implications of your proposition.
It means that you should define a notion of something like
'non-expression', because, you goal for associativity
is to be able to write
char*p ="foo";
*(p-1+1)
It means that p-1 is no more an expression (invalid),
but p+1-1 is one...
That is to say, p-1+1 does not mean (p-1)+1 but
p+(-1+1).
And what about (--p+1), (-1+p+1), (1+p-1) ?

Marc Boyer
 
S

Simon Biber

Francois said:
Are these programs correct ?

#include <stdio.h>
unsigned char a[2] = {1,2};
int main(void) {
unsigned char j;
for(j=1; j<=2; ++j)
printf("%u\n", *( a+j-1 ));
return 0; }

No problems here, it is acceptable to calculate a pointer to one element
past the end of an array.

#include <stdio.h>
unsigned char a[2] = {1,2};
int main(void) {
unsigned char j;
for(j=1; j<=2; ++j)
printf("%u\n", *( a-1+j ));
return 0; }

This one is wrong, it is not acceptable to calculate a pointer to one
element before the beginning of an array.

#include <stdio.h>
unsigned char a[2] = {1,2};
int main(void) {
unsigned char j;
for(j=1; j<=2; ++j)
printf("%u\n", *( a+(j-1) ));
return 0; }

This one is fine, you never calculate an invalid pointer at all.
rot-13 spoiler: bayl gur ynfg bar vf pbeerpg.

Undeciphered: only the last one is correct.

No, the first one is fine too.
One compiler I use generates correct and tight code for the
second form; but it fails for *(-1+a+j) [not due to an
architectural restriction, but due to a plain compiler bug].

There is no "correct" code for the second; both the second and *(-1+a+j)
have undefined behaviour, for the same reason.
Isn't it a shame C programming is so complex ? Given that on
most platforms, pointer arithmetic is associative, and so many
programs out there assume it blindly, is not it time for a
future C standard to waive these restrictions on pointer
associativity in at least a branch of the standard, say with
a predefined constant __ASSOCIATIVE_POINTERS__ ?

When you speak of the associativity of "pointer arithmetic", you are
really conflating two things: integer arithmetic and pointer arithmetic.
Pointer arithmetic cannot be associative, because the syntax does not
even allow constructs like
pointer1 op pointer2 op pointer3
(where both 'op's are the same operator). If op were '+', then it is a
constraint violation as two pointers cannot be added together. If op
were '-', the result of two pointers being subtracted is an integer,
from which you cannot subtract a pointer.

Remember that there are no restrictions on the behaviour of a program
with undefined behaviour; it may behave as you expect, or not.
 
J

Jordan Abel

Francois said:
Are these programs correct ?

#include <stdio.h>
unsigned char a[2] = {1,2};
int main(void) {
unsigned char j;
for(j=1; j<=2; ++j)
printf("%u\n", *( a+j-1 ));
return 0; }

No problems here, it is acceptable to calculate a pointer to one element
past the end of an array.

#include <stdio.h>
unsigned char a[2] = {1,2};
int main(void) {
unsigned char j;
for(j=1; j<=2; ++j)
printf("%u\n", *( a-1+j ));
return 0; }

This one is wrong, it is not acceptable to calculate a pointer to one
element before the beginning of an array.

Note that a-(1-j), however, would be correct, i believe.

[more stuff snipped]
When you speak of the associativity of "pointer arithmetic", you are
really conflating two things: integer arithmetic and pointer arithmetic.
Pointer arithmetic cannot be associative, because the syntax does not
even allow constructs like
pointer1 op pointer2 op pointer3
(where both 'op's are the same operator). If op were '+', then it is a
constraint violation as two pointers cannot be added together. If op
were '-', the result of two pointers being subtracted is an integer,
from which you cannot subtract a pointer.

Remember that there are no restrictions on the behaviour of a program
with undefined behaviour; it may behave as you expect, or not.

It would be simple enough, though, to force compilers to collate all the
integer components of a pointer arithmetic expression into a single
value which is then added to the pointer, which is really what he is
requesting.

i.e. for arbitrary

i1-i2+p+i3-i4, force that to become p+(i1-i2+i3-i4)
 
S

Simon Biber

Jordan said:
It would be simple enough, though, to force compilers to collate all the
integer components of a pointer arithmetic expression into a single
value which is then added to the pointer, which is really what he is
requesting.

i.e. for arbitrary

i1-i2+p+i3-i4, force that to become p+(i1-i2+i3-i4)

Conversely, it's simple enough to ask programmers to follow this rule
anyway, always putting the pointer at the beginning of such an expression.

Anyone who wrote i1-i2+p+i3-i4 in a real program should be shot. Make it
clear and self-descriptive. Having four different offsets added to a
pointer is a little excessive.

My worst so far is something like:

unsigned short *
get(unsigned short *array, int x, int y, int z)
{
return array + x
+ y * mapWidth
+ z * mapWidth * mapHeight;
}

Actually, it was C++ code and used references instead of pointers, but
you get the idea.
 
P

pete

Simon said:
Jordan Abel wrote:
Conversely, it's simple enough to ask programmers to follow this rule
anyway,
always putting the pointer at the beginning of such an expression.

Actually,
placing the pointer after a sequence of integer additions
avoids problems better.

(i1 + i2 + p) only depends on the final sum
(p + i1 + i2) also depends on i1 being
neither negative nor excessively large.
 
K

Keith Thompson

pete said:
Actually,
placing the pointer after a sequence of integer additions
avoids problems better.

(i1 + i2 + p) only depends on the final sum
(p + i1 + i2) also depends on i1 being
neither negative nor excessively large.

p + (i1 + i2) is an improvement on both.
 

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
473,755
Messages
2,569,537
Members
45,021
Latest member
AkilahJaim

Latest Threads

Top