Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #95168 > unrolled thread
| Started by | asetofsymbols@gmail.com |
|---|---|
| First post | 2016-10-23 08:11 -0700 |
| Last post | 2016-10-24 13:34 -0700 |
| Articles | 20 on this page of 55 — 12 participants |
Back to article view | Back to comp.lang.c
pointers asetofsymbols@gmail.com - 2016-10-23 08:11 -0700
Re: pointers Richard Heathfield <rjh@cpax.org.uk> - 2016-10-23 16:26 +0100
Re: pointers asetofsymbols@gmail.com - 2016-10-23 10:35 -0700
Re: pointers Ike Naar <ike@iceland.freeshell.org> - 2016-10-23 17:47 +0000
Re: pointers asetofsymbols@gmail.com - 2016-10-25 12:55 -0700
Re: pointers "James R. Kuyper" <jameskuyper@verizon.net> - 2016-10-23 13:58 -0400
Re: pointers BartC <bc@freeuk.com> - 2016-10-24 00:55 +0100
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-23 17:27 -0700
Re: pointers BartC <bc@freeuk.com> - 2016-10-24 11:53 +0100
Re: pointers supercat@casperkitty.com - 2016-10-24 07:29 -0700
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-24 08:55 -0700
Re: pointers Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-24 14:02 -0700
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-24 14:42 -0700
Re: pointers Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-25 08:56 -0700
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-25 12:17 -0700
Re: pointers Tim Rentsch <txr@alumni.caltech.edu> - 2016-10-26 06:37 -0700
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-24 08:49 -0700
Re: pointers BartC <bc@freeuk.com> - 2016-10-24 17:25 +0100
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-24 09:52 -0700
Re: pointers BartC <bc@freeuk.com> - 2016-10-24 18:15 +0100
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-24 12:20 -0700
Re: pointers BartC <bc@freeuk.com> - 2016-10-24 20:58 +0100
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-24 13:16 -0700
Re: pointers BartC <bc@freeuk.com> - 2016-10-24 23:53 +0100
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-25 13:38 -0700
Re: pointers BartC <bc@freeuk.com> - 2016-10-25 23:06 +0100
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-25 15:39 -0700
Re: pointers BartC <bc@freeuk.com> - 2016-10-26 00:26 +0100
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-25 16:44 -0700
Re: pointers BartC <bc@freeuk.com> - 2016-10-26 01:02 +0100
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-25 17:35 -0700
Re: pointers Ike Naar <ike@iceland.freeshell.org> - 2016-10-26 06:27 +0000
Re: pointers BartC <bc@freeuk.com> - 2016-10-26 12:47 +0100
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-26 09:05 -0700
Re: pointers BartC <bc@freeuk.com> - 2016-10-26 18:46 +0100
Re: pointers supercat@casperkitty.com - 2016-10-26 11:44 -0700
Re: pointers BartC <bc@freeuk.com> - 2016-10-26 20:12 +0100
Re: pointers BartC <bc@freeuk.com> - 2016-10-26 20:30 +0100
Re: pointers supercat@casperkitty.com - 2016-10-26 13:02 -0700
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-26 11:52 -0700
Re: pointers Ike Naar <ike@iceland.freeshell.org> - 2016-10-26 19:11 +0000
Re: pointers BartC <bc@freeuk.com> - 2016-10-26 21:25 +0100
Re: pointers "James R. Kuyper" <jameskuyper@verizon.net> - 2016-10-25 18:56 -0400
Re: pointers "James R. Kuyper" <jameskuyper@verizon.net> - 2016-10-25 19:12 -0400
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-25 16:31 -0700
Re: pointers Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-10-24 21:36 +0100
Re: pointers BartC <bc@freeuk.com> - 2016-10-25 16:54 +0100
Re: pointers Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-10-25 19:09 +0100
Re: pointers supercat@casperkitty.com - 2016-10-24 11:33 -0700
Re: pointers Keith Thompson <kst-u@mib.org> - 2016-10-24 12:22 -0700
Re: pointers James Kuyper <jameskuyper@verizon.net> - 2016-10-24 10:23 -0400
Re: pointers "James R. Kuyper" <jameskuyper@verizon.net> - 2016-10-23 12:31 -0400
Re: pointers Richard Heathfield <rjh@cpax.org.uk> - 2016-10-23 17:38 +0100
Re: pointers Lorinczy Zsigmond <zsiga@nospam.for.me> - 2016-10-24 14:02 +0200
Re: pointers John Bode <jfbode1029@gmail.com> - 2016-10-24 13:34 -0700
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2016-10-24 12:20 -0700 |
| Message-ID | <ln60ohblkv.fsf@kst-u.example.com> |
| In reply to | #95236 |
BartC <bc@freeuk.com> writes:
> On 24/10/2016 17:52, Keith Thompson wrote:
>> BartC <bc@freeuk.com> writes:
>>> And yes I can see this being used, even if it's just to illustrate an
>>> example like this (you'll need to imagine the spaces between &s):
>>>
>>> int **pointer;
>>>
>>> **pointer; // 3 net derefs (one is always implicit with
>>> // variables in HLLs); result: int
>>> &**pointer; // 2 net derefs; int* ( *pointer)
>>> &&**pointer; // 1 net deref; int** ( pointer)
>>> &&&**pointer; // 0 net derefs; int*** ( &pointer)
>>> &&&&**pointer; // -1 net derefs: error (&&pointer)
>>
>> So the only reason you can think of to use those constructs is to
>> illustrate them? That's hardly a good reason to add them to the
>> language.
>>
>> The unary & operator yields the address of its operand.
>
> What does that mean?
The operand must be an lvalue, which means it's an expression that
designates an object. It yields the address of that object. (Or the
operand can be a function designator, but that's not the case we're
discussing.)
> And how does it work with &**pointer?
Exactly the same way it works for any other operand, except that the
special case rule in 6.5.3.2p3 kicks in. What's the point of these
questions?
> Because **pointer would do a double dereference to get to the operand.
> Are you saying now that the & operator effectively cancels that second
> dereference?
Does the word "now" imply that I'm saying something inconsistent with
what I've said before? &**pointer is equivalent to *pointer, except
that the constraints on the operators still apply and the result is not
an lvalue.
> If so, then & is behaving just as I suggested: removing a dereference,
> while * adds one. (Rather than only giving the address of a named
> operand with no intervening * ops.)
>
> Then there is no reason why & & can't remove both dereferences.
Yes there is. The unary & operator doesn't just "remove a dereference".
It yields the address of its operand, which must be an lvalue.
> The resulting
>> expression is not an lvalue, so another unary & cannot be applied to it.
>
> Why is **pointer an lvalue but not *pointer?
Both **pointer and *pointer are lvalues. Where did you get the idea
that *pointer isn't an lvalue?
> **pointer is an an rvalue that can have & in front to yield the
> equivalent of *pointer.
>
> *pointer is an rvalue that can have & in front to yield the equivalent
> of pointer.
>
> But you can't have **pointer as an rvalue that can have & & in front to
> yield the equivalent of pointer? That is, with the first & yielding
> *pointer, and the second 'pointer'.
I don't know what you mean by "rvalue". The standard doesn't use the
term, but defines it in a footnote as the "value of an expression".
*pointer and **pointer are both lvalues (assuming they're valid).
The unary & operator requires an lvalue (or function designator, but
we'll ignore that for now) as its operand. The resulting expression is
not an lvalue. Therefore `& & pointer` is not valid; it's a constraint
violation. The special case described in N1570 6.5.3.2p3 does not
change that.
If you don't believe that, then you're wrong. If you merely don't
*like* it, then you're certainly entitled to that preference, but I have
yet to see a valid basis for it.
You seem to be inventing a principle that the unary * and & operators
should cancel each other out when combined in arbitrary ways. There is
no such principle in C.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-10-24 20:58 +0100 |
| Message-ID | <nulp42$nqg$1@dont-email.me> |
| In reply to | #95239 |
On 24/10/2016 20:20, Keith Thompson wrote: > BartC <bc@freeuk.com> writes: >> On 24/10/2016 17:52, Keith Thompson wrote: >>> BartC <bc@freeuk.com> writes: >>>> And yes I can see this being used, even if it's just to illustrate an >>>> example like this (you'll need to imagine the spaces between &s): >>>> >>>> int **pointer; >>>> >>>> **pointer; // 3 net derefs (one is always implicit with >>>> // variables in HLLs); result: int >>>> &**pointer; // 2 net derefs; int* ( *pointer) >>>> &&**pointer; // 1 net deref; int** ( pointer) >>>> &&&**pointer; // 0 net derefs; int*** ( &pointer) >>>> &&&&**pointer; // -1 net derefs: error (&&pointer) >>> >>> So the only reason you can think of to use those constructs is to >>> illustrate them? That's hardly a good reason to add them to the >>> language. >>> >>> The unary & operator yields the address of its operand. >> >> What does that mean? > > The operand must be an lvalue, which means it's an expression that > designates an object. It yields the address of that object. But &**pointer yields the address of the int value designated by **pointer. That address is itself stored in an object and can also be written as *pointer. So &**pointer and *pointer yield the same value, the same type, and the same object. Why then I can only put a & in front of *pointer, but not in front of &**pointer which is the same thing? > &**pointer is equivalent to *pointer, So you agree... except > that the constraints on the operators still apply and the result is not > an lvalue. ... then what IS the difference between the two? Is it just the C standard decided there ought to be a difference just for the hell of it? > Both **pointer and *pointer are lvalues. Where did you get the idea > that *pointer isn't an lvalue? What's &**pointer then? > You seem to be inventing a principle that the unary * and & operators > should cancel each other out when combined in arbitrary ways. There is > no such principle in C. The trouble is, that makes sense, and leads to consistency and orthogonality. Doing anything else doesn't. I wouldn't be bothered so much if C insisted that & can only be followed by the name of an object. That's a reasonable simplification especially for 1970. But since C appears to allow this: *&*&*&*&*&*&*&*&*&*&*&*&pointer=0; then why not more silliness! -- bartc
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2016-10-24 13:16 -0700 |
| Message-ID | <lnshrla4et.fsf@kst-u.example.com> |
| In reply to | #95241 |
BartC <bc@freeuk.com> writes:
> On 24/10/2016 20:20, Keith Thompson wrote:
>> BartC <bc@freeuk.com> writes:
>>> On 24/10/2016 17:52, Keith Thompson wrote:
>>>> BartC <bc@freeuk.com> writes:
>>>>> And yes I can see this being used, even if it's just to illustrate an
>>>>> example like this (you'll need to imagine the spaces between &s):
>>>>>
>>>>> int **pointer;
>>>>>
>>>>> **pointer; // 3 net derefs (one is always implicit with
>>>>> // variables in HLLs); result: int
>>>>> &**pointer; // 2 net derefs; int* ( *pointer)
>>>>> &&**pointer; // 1 net deref; int** ( pointer)
>>>>> &&&**pointer; // 0 net derefs; int*** ( &pointer)
>>>>> &&&&**pointer; // -1 net derefs: error (&&pointer)
>>>>
>>>> So the only reason you can think of to use those constructs is to
>>>> illustrate them? That's hardly a good reason to add them to the
>>>> language.
>>>>
>>>> The unary & operator yields the address of its operand.
>>>
>>> What does that mean?
>>
>> The operand must be an lvalue, which means it's an expression that
>> designates an object. It yields the address of that object.
>
> But &**pointer yields the address of the int value designated by **pointer.
Yes.
> That address is itself stored in an object and can also be written as
> *pointer.
No, it's not stored in an object. Why do you think it is?
> So &**pointer and *pointer yield the same value, the same type, and the
> same object.
Same value, yes. Same type, yes. Same object, no. *pointer is an
lvalue that designates the object pointed to by `pointer`. &**pointer
is not an value; evaluating it yields the address of an object, but it
is not an lvalue and does not designate an object.
Similarly, given:
int n = 25;
the expressions `n` and `25` yield the same value and the same type, but
only one of them designates an object.
> Why then I can only put a & in front of *pointer, but not in front of
> &**pointer which is the same thing?
Because *pointer is an lvalue and &**pointer is not. Are you having
difficulty understanding this, believing it, or accepting it?
>> &**pointer is equivalent to *pointer,
>
> So you agree...
>
> except
>> that the constraints on the operators still apply and the result is not
>> an lvalue.
>
> ... then what IS the difference between the two? Is it just the C
> standard decided there ought to be a difference just for the hell of it?
>
>> Both **pointer and *pointer are lvalues. Where did you get the idea
>> that *pointer isn't an lvalue?
>
> What's &**pointer then?
Oh, come on, you can figure that out.
>> You seem to be inventing a principle that the unary * and & operators
>> should cancel each other out when combined in arbitrary ways. There is
>> no such principle in C.
>
> The trouble is, that makes sense, and leads to consistency and
> orthogonality. Doing anything else doesn't.
"A foolish consistency is the hobgoblin of little minds"
-- Ralph Waldo Emerson.
> I wouldn't be bothered so much if C insisted that & can only be followed
> by the name of an object. That's a reasonable simplification especially
> for 1970.
Again, the operand of & must be an lvalue, an expression that
(potentially) desigates an object. Restricting it to the "name of an
object" (do you mean a single identifier?) would be foolish. I have no
clue how 1970 is relevant.
> But since C appears to allow this:
>
> *&*&*&*&*&*&*&*&*&*&*&*&pointer=0;
>
> then why not more silliness!
Why more silliness? If you don't like the fact that
*&*&*&*&*&*&*&*&*&*&*&*&pointer=0;
is valid, what restriction would you have the language impose to ban it?
Should `- - - - - - - - - - - - - - - - 42` be illegal?
The operand of unary & must be an lvalue (or a function designator).
The answers to most your silly questions follow from that simple rule.
Finally, I would seriously appreciate an answer to the following.
Exactly what problem do you have with all this? Do you (a) not believe
me when I tell you what the standard actually says, or (b) not accept
that the standard *means* what it says, or (c) simply dislike what the
standard says?
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-10-24 23:53 +0100 |
| Message-ID | <num3c9$jso$1@dont-email.me> |
| In reply to | #95242 |
On 24/10/2016 21:16, Keith Thompson wrote:
> BartC <bc@freeuk.com> writes:
>> But &**pointer yields the address of the int value designated by **pointer.
>
> Yes.
>
>> That address is itself stored in an object and can also be written as
>> *pointer.
>
> No, it's not stored in an object. Why do you think it is?
Take int **pointer with a layout like this at the following 'addresses':
pointer: 1000:[2000] pointer to pointer to int at 1000
2000:[3000] pointer to int at 2000
3000:[7777] int at 3000 containing value 7777
>> So &**pointer and *pointer yield the same value, the same type, and the
>> same object.
And the values resulting from various expressions:
pointer 2000
*pointer 3000 LVALUE according to your posts
**pointer 7777 LVALUE "
&pointer 1000
&*pointer 2000
&**pointer 3000 NOT LVALUE "
& &**pointer 2000 ?
The 3000 from *pointer and the 3000 from &**pointer are the same value
and the same type. Neither are the actual stored 3000, but a copy of it
used as a transient rvalue existing somewhere in the workspace of the
computer (registers, stack etc).
One of these however can have & added in front, and the other can't.
Why? Because *pointer is apparently an Lvalue, but &**pointer isn't. And
why isn't it? Because it is Written. Not really very convincing...
Actually I find your statements as to what is and what isn't an Lvalue
confusing. I originally had LVALUE/NOT LVALUE above the other way around
before I looked again at your posts.
I've always thought passing a writeable Lvalue to functions often
involved adding in a & to an expression. Now you say I have to leave out
the & to get the Lvalue!
> Similarly, given:
> int n = 25;
> the expressions `n` and `25` yield the same value and the same type, but
> only one of them designates an object.
We're talking about things that might be reasonably be expected to have
addresses; not numeric literals which usually don't.
> Finally, I would seriously appreciate an answer to the following.
> Exactly what problem do you have with all this? Do you (a) not believe
> me when I tell you what the standard actually says, or (b) not accept
> that the standard *means* what it says, or (c) simply dislike what the
> standard says?
No problem. I'm just intrigued. The language implementations I've done
work differently, that's all. Here's some of the examples in my language
(^ means dereference):
int r = 7777
ref int q = &r
ref ref int p = &q
println p^^
println &p^^
println &&p^^
println &&&p^^
p^^ := 8888
println p^^
&&&&&p^^^^^^^ := 9999
println p^^
And here's the C generated by that:
int r = 7777;
int * q = &r;
int * * p = &q;
printf("%d\n", **p); // 7777
printf("%p\n", *p);
printf("%p\n", p);
printf("%p\n", &p);
**p = 8888;
printf("%d\n",**p); // 8888
**p = 9999;
printf("%d\n",**p); // 9999
Notice all & and ^ ops have been balanced out so that only the net deref
or address-of ops make it through to the C. The idea that & and * remove
or add derefs just sort of works.
As for a real use-case, say M is a macro accessing some element of a
data structure. But if you want to pass a pointer to it to a function,
then you might expect to be able to write this:
&M
However, because of these rules, you now have to be aware of what's
inside M, because if it happens to start with with & or (&, then it
won't work. In my language with a more casual approach, it will.
Here's another: you want this expression:
(a ? &b : &c);
but the & is applied twice to each internal element. Why can't you write
this:
&(a ? b : c);
This doesn't work; but the M example above may contain just such an
expression. And again, in my language, this works (admittedly to my
surprise; the & just propagates inside the expression).
So there do appear to be advantages to doing things the way I've suggested.
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2016-10-25 13:38 -0700 |
| Message-ID | <lnlgxc88q0.fsf@kst-u.example.com> |
| In reply to | #95250 |
BartC <bc@freeuk.com> writes:
[...]
> The 3000 from *pointer and the 3000 from &**pointer are the same value
> and the same type. Neither are the actual stored 3000, but a copy of
> it used as a transient rvalue existing somewhere in the workspace of
> the computer (registers, stack etc).
>
> One of these however can have & added in front, and the other can't.
>
> Why? Because *pointer is apparently an Lvalue, but &**pointer
> isn't. And why isn't it? Because it is Written. Not really very
> convincing...
>
> Actually I find your statements as to what is and what isn't an Lvalue
> confusing. I originally had LVALUE/NOT LVALUE above the other way
> around before I looked again at your posts.
The idea of an "lvalue" can be a bit confusing, particularly since the
standard went through two flawed definitions before settling on the
current one. And the standard's definition differs from the original
meaning.
Leaving aside the history, an lvalue is "an expression (with an object
type other than void) that potentially designates an object". (The word
"potentially" had to be added so that the lvalue-ness of an expression
can be determined at compile time.)
The name is inspired by the idea that an "lvalue" is something that can
appear on the left side of an assignment, though that doesn't cover all
cases. And note that designating an object is not the same as pointing
to an object. An lvalue can be the *name* of an object. It's a kind of
expression, not a value.
The unary "&" operator can only be applied to an lvalue; it yields the
address of an object, so its operand must designate an object (I'm
ignoring function designators). The value that results from the unary
"&" operator is an address that points to an object, but it's not the
name of an object, so it's not an lvalue.
The special case in N1570 6.5.3.2 that talks about `&*foo` not being
evaluated doesn't affect any of this, and it's not intended to. All the
constraints on the operands still apply, and the expression `&*foo` is
not an value -- because `&anything` is never an lvalue. That special
case was added to allow something like this:
int arr[10];
int *p;
for (p = &arr[0]; p <= &arr[10]; p ++) ...
to have defined behavior; see the recent discussion in comp.std.c.
The & and * operators are not simply inverses of each other than you can
use in pairs in any way you like.
> I've always thought passing a writeable Lvalue to functions often
> involved adding in a & to an expression. Now you say I have to leave
> out the & to get the Lvalue!
An expression passed to a function as an argument is never evaluated as
an lvalue. If it happens to be one, then the lvalue conversion
described in N1570 6.3.2.1p2 is applied to it. Function arguments are
passed by value.
You can of course pass `&foo` to a function if it's of the type the
function is expecting, or `foo` if that's what the function is
expecting.
>> Similarly, given:
>> int n = 25;
>> the expressions `n` and `25` yield the same value and the same type, but
>> only one of them designates an object.
>
> We're talking about things that might be reasonably be expected to
> have addresses; not numeric literals which usually don't.
>
>> Finally, I would seriously appreciate an answer to the following.
>> Exactly what problem do you have with all this? Do you (a) not believe
>> me when I tell you what the standard actually says, or (b) not accept
>> that the standard *means* what it says, or (c) simply dislike what the
>> standard says?
>
> No problem. I'm just intrigued. The language implementations I've done
> work differently, that's all. Here's some of the examples in my
> language (^ means dereference):
[snip]
Um, I think your answer is (c), but it's hard to tell. Of course other
languages are different; that's what makes them other languages.
[...]
> So there do appear to be advantages to doing things the way I've suggested.
There's no point in discussing any advantages until we understand what
the standard currently says.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-10-25 23:06 +0100 |
| Message-ID | <nuol16$idr$1@dont-email.me> |
| In reply to | #95310 |
On 25/10/2016 21:38, Keith Thompson wrote: > BartC <bc@freeuk.com> writes: >> No problem. I'm just intrigued. The language implementations I've done >> work differently, that's all. Here's some of the examples in my >> language (^ means dereference): > [snip] > > Um, I think your answer is (c), but it's hard to tell. Of course other > languages are different; that's what makes them other languages. The language I gave examples in isn't that different; it's at the same level as C and has to solve many of the same problems. With the alternative approach to mixing & and *, the result is more expressiveness, fewer problems and more useful diagnostics (so you get a genuine error when the number of & or * is wrong for the type, not when you hit some arbitrary restriction in the language). That C doesn't allow that expressiveness isn't a big deal as the terms involved can usually be rewritten into something that's legal. But it does seem rather unsatisfactory given that in other places C /does/ allow any number of chained * ops which do not match the type of the term they operate on. Example: f is a function with no associated pointers, but *f, **f, ***f are all legal. As is &**f. But not & &**f which ought to be equivalent of f.) >> So there do appear to be advantages to doing things the way I've suggested. > > There's no point in discussing any advantages until we understand what > the standard currently says. The advantage is obvious. You don't need to explain why &*p is allowed but not & &**p or *&p! -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2016-10-25 15:39 -0700 |
| Message-ID | <lnd1io8354.fsf@kst-u.example.com> |
| In reply to | #95312 |
BartC <bc@freeuk.com> writes:
> On 25/10/2016 21:38, Keith Thompson wrote:
>> BartC <bc@freeuk.com> writes:
>
>>> No problem. I'm just intrigued. The language implementations I've done
>>> work differently, that's all. Here's some of the examples in my
>>> language (^ means dereference):
>> [snip]
>>
>> Um, I think your answer is (c), but it's hard to tell. Of course other
>> languages are different; that's what makes them other languages.
>
> The language I gave examples in isn't that different; it's at the same
> level as C and has to solve many of the same problems.
Can you please give a direct answer the question I asked upthread?
Finally, I would seriously appreciate an answer to the following.
Exactly what problem do you have with all this? Do you (a)
not believe me when I tell you what the standard actually says,
or (b) not accept that the standard *means* what it says, or
(c) simply dislike what the standard says?
> With the alternative approach to mixing & and *, the result is more
> expressiveness, fewer problems and more useful diagnostics (so you get a
> genuine error when the number of & or * is wrong for the type, not when
> you hit some arbitrary restriction in the language).
I see nothing arbitrary about the restrictions. & must be applied to an
lvalue, and does not yield an lvalue. * may be applied either to a
non-lvalue or to an lvalue, and yields an lvalue. (Again, ignoring
function designators.) Both of those make perfectly good sense to me,
to the extent that I didn't have to refer to the standard to write this
paragraph (though I did check it to make sure).
I see no way that relaxing those rules would improve expressiveness. I
can think of no *meaningful* expression that could be expressed with
looser rules that can't already be expressed (unless you want to add the
ability to implicitly create objects from expressions, thus allowing
things like &25).
> That C doesn't allow that expressiveness isn't a big deal as the terms
> involved can usually be rewritten into something that's legal.
Not only legal, but clearer. Given `int **ptr;`, you can't legally
write `& &*ptr`, but you can write `&ptr`.
> But it does seem rather unsatisfactory given that in other places C
> /does/ allow any number of chained * ops which do not match the type of
> the term they operate on. Example:
>
> f is a function with no associated pointers, but *f, **f, ***f are all
> legal. As is &**f. But not & &**f which ought to be equivalent of f.)
Because a function designator is implicitly converted to the address
of the function in most contexts. `& &**f` doesn't make sense,
because `&**f` is not an lvalue, so it doesn't designate anything
that has an address. My solution is simple: it would never occur
to me to write `& &**f`, so I don't have to care what it might mean.
The special-case rule that allows collapsing `&*foo` to `foo` in some
restricted circumstances is intended to cover a quite narrow use case.
You're trying to extend it to use cases that don't really mean anything.
Shall I cite Emerson again?
>>> So there do appear to be advantages to doing things the way I've suggested.
>>
>> There's no point in discussing any advantages until we understand what
>> the standard currently says.
>
> The advantage is obvious. You don't need to explain why &*p is allowed
> but not & &**p or *&p!
You're the only person I've had to explain that to. And I'm still not
sure whether you don't understand the explanation or just don't like it.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-10-26 00:26 +0100 |
| Message-ID | <nuopn1$57r$1@dont-email.me> |
| In reply to | #95313 |
On 25/10/2016 23:39, Keith Thompson wrote: > BartC <bc@freeuk.com> writes: >> The advantage is obvious. You don't need to explain why &*p is allowed >> but not & &**p or *&p! > > You're the only person I've had to explain that to. And I'm still not > sure whether you don't understand the explanation or just don't like it. It's simple: you think of & as something that needs to be applied to some 'lvalue' according to a lawyerly account in a language reference. The /C/ language reference. I don't think like that at all. I just use & either to get the address of a storage location designated by an expression, or to offset a pointer operation. I don't care what the standard says! I'm not that bothered what language it is either. When you're dealing with explicit pointers then the issues of applying address-of or dereferencing pointers are universal. Apparently C is fussy about how & and * are combined. That's fine. My own language isn't, and the generated C code has ref/deref chains 'normalised' so as to be suitable for C's sensitivities. (I've had a lot of practice!) So no problem. -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2016-10-25 16:44 -0700 |
| Message-ID | <ln4m408048.fsf@kst-u.example.com> |
| In reply to | #95316 |
BartC <bc@freeuk.com> writes:
> On 25/10/2016 23:39, Keith Thompson wrote:
>> BartC <bc@freeuk.com> writes:
>
>>> The advantage is obvious. You don't need to explain why &*p is allowed
>>> but not & &**p or *&p!
>>
>> You're the only person I've had to explain that to. And I'm still not
>> sure whether you don't understand the explanation or just don't like it.
>
> It's simple: you think of & as something that needs to be applied to
> some 'lvalue' according to a lawyerly account in a language
> reference. The /C/ language reference.
You're distorting what I said. The C standard is the definitive
reference for the C language, but the rules it gives for the unary
"&" operator also *make sense* to me.
> I don't think like that at all. I just use & either to get the address
> of a storage location designated by an expression, or to offset a
> pointer operation. I don't care what the standard says!
I suggest that's why you have such difficulty understanding or accepting
the actual rules. You think `& &*foo` makes some kind of sense, and you
refuse to accept the reasonably straightforward reasons that it doesn't.
> I'm not that bothered what language it is either. When you're dealing
> with explicit pointers then the issues of applying address-of or
> dereferencing pointers are universal.
Not really. Applying address-of makes sense only when there's an object
whose address you want.
> Apparently C is fussy about how & and * are combined. That's fine. My
> own language isn't, and the generated C code has ref/deref chains
> normalised' so as to be suitable for C's sensitivities. (I've had a
> lot of practice!)
>
> So no problem.
Do me a favor. Next time I try to explain something to you, please tell
me right away that you don't care about it. Don't waste time telling me
that you don't accept what I'm saying, just tell me you don't care, and
I'll stop. In fact I think I'll just assume that from the start.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-10-26 01:02 +0100 |
| Message-ID | <nuorqb$a9j$1@dont-email.me> |
| In reply to | #95318 |
On 26/10/2016 00:44, Keith Thompson wrote: > BartC <bc@freeuk.com> writes: >> I don't think like that at all. I just use & either to get the address >> of a storage location designated by an expression, or to offset a >> pointer operation. I don't care what the standard says! > > I suggest that's why you have such difficulty understanding or accepting > the actual rules. You think `& &*foo` makes some kind of sense, and you > refuse to accept the reasonably straightforward reasons that it doesn't. Yet if the Standard had slightly different wording, then suddenly it would make sense to you as well! But we'd be dealing with exactly the same objects and operations. >> I'm not that bothered what language it is either. When you're dealing >> with explicit pointers then the issues of applying address-of or >> dereferencing pointers are universal. > > Not really. Applying address-of makes sense only when there's an object > whose address you want. Well in your example of '& &*foo' I'd say that reduces to '&foo' due to the &* cancelling each other. So we have the address of the object foo. Perfectly reasonable. But the small-print in the C standard says that even though the &* in &*foo cancels to result in just foo, you can't apply the second & to '&*foo' as you can with 'foo' itself. You must see that it is the wording in that document that stops this construct being legal, rather than anything wrong with the universal ideas involved with this pointer and address manipulation. I think even Ben Bacarisse agreed with me that the Standard could easily have had a somewhat different rule, where &* elimination was applied recursively, that would have made & &*foo legal. -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2016-10-25 17:35 -0700 |
| Message-ID | <lnwpgw6j6w.fsf@kst-u.example.com> |
| In reply to | #95319 |
BartC <bc@freeuk.com> writes:
> On 26/10/2016 00:44, Keith Thompson wrote:
>> BartC <bc@freeuk.com> writes:
>>> I don't think like that at all. I just use & either to get the address
>>> of a storage location designated by an expression, or to offset a
>>> pointer operation. I don't care what the standard says!
>>
>> I suggest that's why you have such difficulty understanding or accepting
>> the actual rules. You think `& &*foo` makes some kind of sense, and you
>> refuse to accept the reasonably straightforward reasons that it doesn't.
>
> Yet if the Standard had slightly different wording, then suddenly it
> would make sense to you as well! But we'd be dealing with exactly the
> same objects and operations.
>
>>> I'm not that bothered what language it is either. When you're dealing
>>> with explicit pointers then the issues of applying address-of or
>>> dereferencing pointers are universal.
>>
>> Not really. Applying address-of makes sense only when there's an object
>> whose address you want.
>
> Well in your example of '& &*foo' I'd say that reduces to '&foo' due to
> the &* cancelling each other. So we have the address of the object foo.
> Perfectly reasonable.
>
> But the small-print in the C standard says that even though the &* in
> &*foo cancels to result in just foo, you can't apply the second & to
> '&*foo' as you can with 'foo' itself.
>
> You must see that it is the wording in that document that stops this
> construct being legal, rather than anything wrong with the universal
> ideas involved with this pointer and address manipulation.
>
> I think even Ben Bacarisse agreed with me that the Standard could easily
> have had a somewhat different rule, where &* elimination was applied
> recursively, that would have made & &*foo legal.
You're wrong on several points. I will explain further if and only if
you (1) answer the question I asked you before (the choices were (a),
(b), and (c)) *and* (2) you directly ask me to explain. Or you can just
continue to be wrong.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | Ike Naar <ike@iceland.freeshell.org> |
|---|---|
| Date | 2016-10-26 06:27 +0000 |
| Message-ID | <slrn3vfso10j6v.b9e.ike@iceland.freeshell.org> |
| In reply to | #95312 |
On 2016-10-25, BartC <bc@freeuk.com> wrote: > You don't need to explain why &*p is allowed > but not & &**p or *&p! What makes you believe that *&p is not allowed?
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-10-26 12:47 +0100 |
| Message-ID | <nuq549$dp9$1@dont-email.me> |
| In reply to | #95323 |
On 26/10/2016 07:27, Ike Naar wrote: > On 2016-10-25, BartC <bc@freeuk.com> wrote: >> You don't need to explain why &*p is allowed >> but not & &**p or *&p! > > What makes you believe that *&p is not allowed? OK that one is allowed: *&*&*&*p; as is: &*&*&*p; when p is a pointer. But not: ***& & &p; or: & & &***p; // allowed on some compilers when p is T*** If, however, you go through this on paper, striking through * followed by &, or & followed by * with a pencil, and repeating, you end up with just 'p' in all cases. And p doesn't need to be a pointer. On paper. -- bartc
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2016-10-26 09:05 -0700 |
| Message-ID | <lnoa276qow.fsf@kst-u.example.com> |
| In reply to | #95324 |
BartC <bc@freeuk.com> writes:
> On 26/10/2016 07:27, Ike Naar wrote:
>> On 2016-10-25, BartC <bc@freeuk.com> wrote:
>>> You don't need to explain why &*p is allowed
>>> but not & &**p or *&p!
>>
>> What makes you believe that *&p is not allowed?
>
> OK that one is allowed:
>
> *&*&*&*p;
>
> as is:
>
> &*&*&*p;
>
> when p is a pointer. But not:
>
> ***& & &p;
>
> or:
>
> & & &***p; // allowed on some compilers when p is T***
Any compilers that do not diagnose that are non-conforming.
And the simple reason for that has been explained several times.
No doubt the inability to write & & &***p has been a great
inconvenience to you.
> If, however, you go through this on paper, striking through * followed
> by &, or & followed by * with a pencil, and repeating, you end up with
> just 'p' in all cases. And p doesn't need to be a pointer.
>
> On paper.
If I invent an arbitrary rule that doesn't actually exist in the
language, and then execute that rule using pencil and paper, I can
reach any nonsensical conclusion I like. The & and * operators do
not arbitrarily cancel each other out, and your obsession with the
idea that they do or should is absurd.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-10-26 18:46 +0100 |
| Message-ID | <nuqq5u$sas$1@dont-email.me> |
| In reply to | #95327 |
On 26/10/2016 17:05, Keith Thompson wrote: > BartC <bc@freeuk.com> writes: >> & & &***p; // allowed on some compilers when p is T*** > No doubt the inability to write & & &***p has been a great > inconvenience to you. What's the point of allowing &* and *&? I have an idea how that can useful, but I'd be interested in hearing your take first. >> If, however, you go through this on paper, striking through * followed >> by &, or & followed by * with a pencil, and repeating, you end up with >> just 'p' in all cases. And p doesn't need to be a pointer. >> >> On paper. > The & and * operators do > not arbitrarily cancel each other out, and your obsession with the > idea that they do or should is absurd. Well I've successfully used just such a feature for years elsewhere so it's not nonsensical; it makes a lot of sense in fact. (However there was also another feature - auto-dereferenced types - which made repeated & more useful than it would be in C.) -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-10-26 11:44 -0700 |
| Message-ID | <0111c223-4f39-4649-9cbc-387ca701d62c@googlegroups.com> |
| In reply to | #95329 |
On Wednesday, October 26, 2016 at 12:47:09 PM UTC-5, Bart wrote:
> What's the point of allowing &* and *&? I have an idea how that can
> useful, but I'd be interested in hearing your take first.
On some implementations, a void** can be used to access any kind of data
pointer; when targeting such implementations, it may be helpful to be able
implement functions like:
int try_resize(void **p, int new_size)
{
void *oldptr = *p;
void *newptr = realloc(old_ptr, new_size);
if (newptr)
{
*p = newptr;
return 1;
}
else
return 0;
}
Even on platforms where aliasing isn't a problem, however, code using the
above function would need to typecast its argument to void**. One could
avoid the need for a typecast via:
#define try_resize(p,size) try_resize ((void**)(p),(size))
but that would uselessly accept things that weren't pointers to pointers.
If & and * operatons could be nested, that would allow
#define try_resize(p,size) try_resize ((void**)& &**(p),(size))
to accept any kind of double-indirect pointer, but not try to cast something
that wasn't a double-indirect pointer into one.
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-10-26 20:12 +0100 |
| Message-ID | <nuqv5h$gs7$1@dont-email.me> |
| In reply to | #95330 |
On 26/10/2016 19:44, supercat@casperkitty.com wrote:
> On Wednesday, October 26, 2016 at 12:47:09 PM UTC-5, Bart wrote:
>> What's the point of allowing &* and *&? I have an idea how that can
>> useful, but I'd be interested in hearing your take first.
>
> On some implementations, a void** can be used to access any kind of data
> pointer; when targeting such implementations, it may be helpful to be able
> implement functions like:
>
> int try_resize(void **p, int new_size)
> {
> void *oldptr = *p;
> void *newptr = realloc(old_ptr, new_size);
> if (newptr)
> {
> *p = newptr;
> return 1;
> }
> else
> return 0;
> }
>
> Even on platforms where aliasing isn't a problem, however, code using the
> above function would need to typecast its argument to void**. One could
> avoid the need for a typecast via:
>
> #define try_resize(p,size) try_resize ((void**)(p),(size))
>
> but that would uselessly accept things that weren't pointers to pointers.
> If & and * operatons could be nested, that would allow
>
> #define try_resize(p,size) try_resize ((void**)& &**(p),(size))
>
> to accept any kind of double-indirect pointer, but not try to cast something
> that wasn't a double-indirect pointer into one.
I think I get it. A kind of validation technique where you don't know
what the expression is (whether it starts with *s), because macros or
possibly typedefs are involved.
(However, as I deal with chains of & and * in my non-C compiler, all
matched & and * pairs will be eliminated before type-checking is done.
So it couldn't be used for that kind of validation.)
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | BartC <bc@freeuk.com> |
|---|---|
| Date | 2016-10-26 20:30 +0100 |
| Message-ID | <nur07o$l02$1@dont-email.me> |
| In reply to | #95332 |
On 26/10/2016 20:12, BartC wrote:
> On 26/10/2016 19:44, supercat@casperkitty.com wrote:
>> but that would uselessly accept things that weren't pointers to pointers.
>> If & and * operatons could be nested, that would allow
>>
>> #define try_resize(p,size) try_resize ((void**)& &**(p),(size))
> (However, as I deal with chains of & and * in my non-C compiler, all
> matched & and * pairs will be eliminated before type-checking is done.
> So it couldn't be used for that kind of validation.)
That's not quite right: while * (or its equivalent) has to look 'behind'
to see if there is a & which may affect it, that isn't the case with &
which only looks forwards.
So in C:
int A;
enum {B};
*&A; // valid
*&B; // not valid
If you needed A or B to be lvalues, you can't tell just by looking at A;
or B; in the source. But *&A; or *&B; will guard that without affecting
the value.
Probably there are better examples...
But it shows that allowing chains of & and * can't hurt.
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-10-26 13:02 -0700 |
| Message-ID | <1bdc6428-d1ea-4454-96f0-d4598060f7e4@googlegroups.com> |
| In reply to | #95332 |
On Wednesday, October 26, 2016 at 2:12:21 PM UTC-5, Bart wrote:
> (However, as I deal with chains of & and * in my non-C compiler, all
> matched & and * pairs will be eliminated before type-checking is done.
> So it couldn't be used for that kind of validation.)
There are cases in C where taking the address of something is semantically
significant, even if the address is dereferenced immediately and not used
for any other purpose.
unsigned char foo(void)
{
unsigned char x;
return *&x;
}
Use of an uninitialized automatic variable which does not have its address
taken invokes UB, even if the type of the variable is "unsigned char", but
since x has its address taken (and used), the above would be required to
yield some value within the range of unsigned char, without any other
side-effects.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2016-10-26 11:52 -0700 |
| Message-ID | <lnk2cv6iyq.fsf@kst-u.example.com> |
| In reply to | #95329 |
BartC <bc@freeuk.com> writes:
> On 26/10/2016 17:05, Keith Thompson wrote:
>> BartC <bc@freeuk.com> writes:
>
>>> & & &***p; // allowed on some compilers when p is T***
>
>> No doubt the inability to write & & &***p has been a great
>> inconvenience to you.
>
> What's the point of allowing &* and *&? I have an idea how that can
> useful, but I'd be interested in hearing your take first.
What would be the point of disallowing them? The semantics of
the "&" operator are such that it can be applied to the result
of a "*" operator, and vice versa. Expressions are built up from
subexpressions in an arbitrary manner (subject to any constraints).
I see no reason for the language to go out of its way to impose
arbitrary restrictions. (Nor do I see any reason for it to to out
of its way to make arbitrary nonsensical constructs valid.)
It probably doesn't make much sense to write `- - - - - - - - 0`,
but it would make even less sense for the language to go out of
its way to disallow it. Any arbitrary restriction intended solely
to prevent you from doing something silly is likely to prevent you
from doing something useful. And to forestall your likely response,
I do not consider the fact that the unary "&" operator does not
yield an lvalue, or that it requires an lvalue as its operand,
to be arbitrary; both rules are part of the fundamental semantics
of the operator, and are applied consistently.
[snip]
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
Back to top | Article view | comp.lang.c
csiph-web