Why multiplication not allowed?

  • Thread starter Vijay Kumar R Zanvar
  • Start date
P

Peter Nilsson

Kevin Goodsell said:
FYI, there is a guarantee in C99 that an object pointer will fit in a
intptr_t, if that type is provided.

More specifically, as an aside, the conversion back to an equivalent
void * is guaranteed, something which isn't the case for other integer
types, not even intmax_t.
 
K

Kevin Goodsell

Peter said:
More specifically, as an aside, the conversion back to an equivalent
void * is guaranteed, something which isn't the case for other integer
types, not even intmax_t.

Yes, the standard only explicitly says you can convert from void* to
intptr_t, then back to void* and the result will compare equal to the
original void*. Other pointer types *should* also work (by which I mean
that it would make sense, and people probably expect them to work), but
I don't know if or where in the standard this is guaranteed.

As for intmax_t, I would expect that it could be used in place of
intptr_t as long as intptr_t exists - my reasoning being that the only
thing which would prevent an integer type from holding a pointer value
without loss is if the integer type is not wide enough, and intmax_t
must be at least as wide as intptr_t. I don't know if that is correct,
though.

I should take a good look at the section of the standard dealing with
conversion between integers and pointers, I guess.

-Kevin
 
J

Jarno A Wuolijoki

If p is a pointer pointing to a memory region of sufficient size,

(p+5)==(p+5*sizeof(*p))

Mixing C and asm sides of brain?-)

right? Likewise for p-5. Then (I suggest),

(p*5)==(5*sizeof(*p))

would be sensible. Not needed, but meaningful, yes?

Not really, but I'd imagine that sizeof(*(p*5)) == 5*sizeof(*p) would
have some odd symmetry, if that's what you're after.. as in:

pointers -> points (index, size)
scalars -> vectors (index, 0)
 
A

August Derleth

Alan said:
You didn't answer the question. What meaning would you ascribe to the
result of the operation?

If you'd read on, you'd have seen that I really wouldn't have. Any more
than I would have been able to ascribe meaning to the result of adding a
random integral value to an arbitrary pointer. My whole point is that in
some languages (not C, but C's immediate ancestors and some languages
not connected with C at all), you can treat a pointer as you would any
other integral type of that width. Which includes doing absolutely
nonsensical things to it.

Obviously, I'm in a minority here. I didn't expect it to be otherwise,
given the bizarreness of the whole notion of multiplication being
applied to pointers.
 
A

August Derleth

Kevin said:
Because the result is *not* meaningful for pointers.

I'm not saying it would be. I'm just saying that some languages allow
it, and that I'm surprised that C isn't one of them.
All I can say to this is that I'm glad you didn't design C.

Me, too. I probably would have designed a language too tied to the PDP's
instruction set and not easily portable to anything else.
You might also be interested in BCPL. I know almost nothing about it,
but I believe I read that it only had 1 type: the machine word. I
imagine this would give you the kind of complete freedom from
hand-holding that you seem to want. (It's also possible that the
language I'm thinking of is B, not BCPL.)

I'm aware of that, and that's partially what I was thinking of. In B and
BCPL, a rather Forth-like notion of `Trust the programmer' pervades the
concept of types. (Or maybe `In Forth, a BCPL-like notion ... ' ;))

C's notion of types is strict enough to be helpful and loose enough to
not be obnoxious, IMHO, even though it occasionally leads to threads
like these.
 
A

August Derleth

Keith said:
August Derleth said:
Kevin Goodsell wrote:
[...]
The question Ben is asking is, what would you propose pointer
multiplication do? How would you define the operation? I can't think
of any way in which multiplying a pointer by any other value would
be useful or even meaningful.

The way I reason is like this: If I take i and assign an address to it
(that is, I make it a pointer), i is the name of a block of memory
that holds a certain string of bits or trits or decimal digits that
compose that address. At this layer of abstraction, it's no different
from an int or a float. Since I can multiply two ints and stand a good
chance at getting a meaningful result, why not two pointers? Or an int
and a pointer?


Because you *can't* multiply two pointers, or an int and a pointer,
and stand a chance at getting a meaningful result.

Which doesn't stop BCPL, for instance. :)
Pointers are not integers. Pointer arithmetic in C is not defined in
terms of treating the bit patterns composing the pointer values as
integers and performing integer arithmetic on them; it's defined in
terms of what object the resulting pointer value points to.

I know that. I am satisfied with the existing pointer arithmetic,
acutally, even though I posited my remarks from the perspective of
changing it.
For example, if p is a pointer, the machine-level operations that are
performed to evaluate the expression (p + 4) depend on the type of p.
If p is a char*, (p + 4) points to a location 4 bytes "after" the
location pointed to by p; if p is an int*, (p + 4) points
4*sizeof(int) bytes "after" the location pointed to by p. If p is a
void*, the expression (p + 4) is illegal (though some compilers may
support it as a language extension (unwisely, IMHO)).

This is where my ideas about multiplication fall down in one respect:
Addition (by positive and negative numbers) is scaled, but there's no
meaningful way to scale multiplication. Or division, for that matter.
And how would you scale the square root?

We could invent ways, surely, but it's hardly worth it.

(If you want to know, I was imagining pointers as being treated like
integers in my imaginary C-like language.)
Another example: On Cray vector machines, a machine address points to
a 64-bit word. The C compiler implements 8-bit chars (CHAR_BIT == 8)
by "cheating" a little. (I put the word "cheating" in quotation marks
because what the C compiler does is perfectly legitimate; it just
doesn't map directly to the underlying hardware.) A char* is
implemented as a word address with a byte offset kludged into the
high-order 3 bits. (I actually don't know how much hardware support
there is for this format.) Multiplying two such pointers makes as
much sense as taking the square root of a struct.

This is fascinating. Which compiler do you use? Does gcc support the
Cray vector machines?

It's fascinating, and it makes my ideas sound rather foolish. You could
multiply two such pointers, but the machine-level semantics would always
be in doubt and the result would be universally meaningless.
If, for some reason, you want to treat the contents of two pointers as
if they were integers, multiply them, and store the resuting integer
bit pattern into a pointer, you can do so. I don't think a cast from
a pointer to an integer of the appropriate size, or vice versa, is
guaranteed to just copy the bits, but it probably does so on most or
all implementations. If you're concerned about that, you can use
memcpy(), which is guaranteed to copy the bits. Using explicit
conversions, you can multiply two pointers (treating the pointers' bit
patterns as integers and treating the resulting integer bit pattern as
a pointer) as easily as you can take the square root of a struct
(treating the struct's bit pattern as a double). The compiler won't
hold your hand while you do this, but it won't stop you. Of course,
you'll invoke undefined behavior, and I can't think of any possible
use for the result.

All of that is fair enough, and it's all I can reasonably expect. After
all, the compiler won't hold my hand, will it? :) memcpy() seems like a
somewhat sideways means of achieving this, but its semantics are
obvious. Whereas the semantics of multiplying two pointers would not be.
 
K

Keith Thompson

August Derleth said:
Keith Thompson wrote: [...]
Because you *can't* multiply two pointers, or an int and a pointer,
and stand a chance at getting a meaningful result.

Which doesn't stop BCPL, for instance. :)

Which is one of the ways C is an improvement over BCPL. :-|

[...]
This is fascinating. Which compiler do you use? Does gcc support the
Cray vector machines?

No, gcc doesn't support the Cray vector machines; Cray has its own C
compiler.
 
G

glen herrmannsfeldt

Barry Schwarz wrote:

(snip)
(snip)

Adding an int to a pointer results in pointing to something a
specified distance further to the "right" in memory.
Subtracting an int from a pointer results in pointing to something a
specified distance further to the "left" in memory.
Subtracting one pointer from another results in how far apart the two
memory locations are.

An expression could be properly absolute or relocatable, even if it
contained multiplication of pointers. The number of uses are small
enough that I am not surprised it isn't allowed. How about:

char *s,*t;
s=2*t-s;
s=3*t-2*s;

(I know some assemblers that allow relocation factors
of -1, 0, 1, or 2.)

-- glen
 
G

glen herrmannsfeldt

James said:
While I've never felt an urge to multiply pointers, there
is a situation where adding them is quite legitimate:
char *rcopy, *q, *r;
. . .
strcpy(rcopy, r);
q = index(r, '*');
. . .
/* Now point to the '*' in the copy */
foobar(rcopy + q - r);

My first C program using index, after using a similar function
in other languages, did something like i=index(r,"*")-r;

It made the NULL test more complicated, though.
(Please don't write in to tell me I forgot to allocate space for rcopy, etc.
This is just a minimal illustration of the point.)
Although the intermediate expression (rcopy + q) has the illegal form
of (ptr + ptr) the net expression is OK.

Well, for (char*), ok.
I was disappointed when gcc rejected my construction like this, depending
on how I parenthesized it. It seems like it shouldn't be hard to support.

Things get more interesting with pointers to larger types.

int *b,*c;
char *a;

a=a+b-c;

Remember that pointer addition is done in units of the type
pointed to. Pointer-pointer is done so that the result is
in such units.

In this case, the result would be different.

Also, consider that the int pointers could (illegally) point
to non-aligned addresses.

-- glen
 
G

glen herrmannsfeldt

Joona I Palaste wrote:

(snip)
Yes, this is an obsolete feature of C. =+ and =- originally meant the
same as += and -=. Whoever designed them that way must have been
drinking something really strong. AFAIK they were dropped when ISO
standardised C.
That the interviewer still clung to the obsolete meanings of those
operators makes me feel that he wasn't the proper person to interview
you about C.


I have used compilers that allowed them for compatibility. I still
always put a space between = and -, like i= -1; to be sure.

(I think the compiler gave a warning, though.)

-- glen
 
S

Sean Kenwrick

Keith Thompson said:
The =+ syntax was dropped long before ISO C; it had vanished by the
time K&R1 was published.

Not many years ago, I used a compiler (VAXC, I think) that allowed the
old =+ syntax, but I think it at least issued a warning about it. (It
also helpfully "corrected" the unrecognized "signed" keyword to
"unsigned".) The oldest C compiler I now have access to (circa 1988)
just treats =+ as a syntax error.
This interview was quite a long time ago (1989), but I remember it well
because of these 'trick' questions that I was asked about C. Perhaps they
were still using a compiler at the company that supported this old
syntax....

Sean
 
G

glen herrmannsfeldt

August Derleth wrote:

(snip)

(snip)

I believe PL/I will let you take the square root of a struct, doing it
element by element. You can also take the square root of a character
string if it has a numeric value.

I wonder why C doesn't allow that.

-- glen
 
D

Dik T. Winter

> Keith Thompson wrote: ....

Actually the high order 16 bits. The low order 48 bits are the memory
address.

None at all. There is *no* hardware support for 8 bit quantities.
>
> This is fascinating. Which compiler do you use? Does gcc support the
> Cray vector machines?

This would be with Cray's C compiler. I do not know whether there is gcc
support for the Cray. It would be a bit foolish to look for gcc on the
Cray as it certainly does not support vectorisation.
 
P

pete

James said:
While I've never felt an urge to multiply pointers, there
is a situation where adding them is quite legitimate:
No.

char *rcopy, *q, *r;
. . .
strcpy(rcopy, r);
q = index(r, '*');
. . .
/* Now point to the '*' in the copy */
foobar(rcopy + q - r);
(Please don't write in to tell me I forgot to
allocate space for rcopy, etc.
This is just a minimal illustration of the point.)

Although the intermediate expression (rcopy + q) has the illegal form
of (ptr + ptr) the net expression is OK.

I was disappointed when gcc rejected my construction like this,
depending on how I parenthesized it.
It seems like it shouldn't be hard to support.

Yes, yes; the better parenthesization would also make the program more
readable. Well nevermind ....

You cite the rule correctly:
"the intermediate expression (rcopy + q)
has the illegal form of (ptr + ptr)"
You make the observation, which corresponds to the rule:
"gcc rejected my construction"

Where do you get this erroneous notion from ? :
"the net expression is OK"
 
P

pete

glen said:
My first C program using index, after using a similar function
in other languages, did something like i=index(r,"*")-r;

It made the NULL test more complicated, though.



Well, for (char*), ok.

What's OK about it ?
Things get more interesting with pointers to larger types.

int *b,*c;
char *a;

a=a+b-c;

That last line of code is a syntax error.
 
C

Christopher Benson-Manica

No. However,
(char *)(p + 5) == (char *)p + 5 * sizeof *p

1) p+5 and p+5*sizeof(*p) are valid constructions, correct?
2) I assume they do not compare as equal because of some implicit
conversion issues?
3) If 2, would you care to elaborate?
4) If 2 and 3, can you tell me what the Standard says...?
5) Does 5+p have the same semantics as p+5?

(thanks!)
It doesn't seem particularly meaningful to me and I don't see why you
think it follows from your first example. Why does `p' change into
'sizeof(*p)' as the operand of binary '*'?

It would allow one to use

malloc( 5*p );

to allocate space for an array of 5 p's. Mostly I was just trying to
counter the suggestion that multiplying an integer and a pointer is a
conceptually meaningless endeavor...
 
C

Christopher Benson-Manica

glen herrmannsfeldt said:
I believe PL/I will let you take the square root of a struct, doing it
element by element. You can also take the square root of a character
string if it has a numeric value.
I wonder why C doesn't allow that.

In that case,

struct p {
char *foo;
char bar;
int:3 baz;
int:2 quux;
};

would likely be quite a challenge to sqrt(). A lot of work for
implementors, certainly...
 
A

Alex Monjushko

Christopher Benson-Manica said:
glen herrmannsfeldt <[email protected]> spoke thus:
In that case,
struct p {
char *foo;
char bar;
int:3 baz;
int:2 quux;
};
would likely be quite a challenge to sqrt(). A lot of work for
implementors, certainly...

Fortunately sqrt will not have to deal with this struct because
it contains syntax errors. Bit-width should be specified for the
member, not its type.
 
K

Kevin Goodsell

Christopher said:
1) p+5 and p+5*sizeof(*p) are valid constructions, correct?

Yes. Both show pointer arithmetic. The integer added to the pointer p is
different in each case, so the result is presumably different.
2) I assume they do not compare as equal because of some implicit
conversion issues?

Not really... they don't compare equal for the same reason i+5 and i+5*4
don't compare equal when i is an integer.
3) If 2, would you care to elaborate?
4) If 2 and 3, can you tell me what the Standard says...?
5) Does 5+p have the same semantics as p+5?

Yes.

-Kevin
 

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

Forum statistics

Threads
474,135
Messages
2,570,783
Members
47,341
Latest member
hanifree

Latest Threads

Top