Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #163857 > unrolled thread

on understanding & and pointer arithmetic

Started byMeredith Montgomery <mmontgomery@levado.to>
First post2021-12-16 11:13 -0300
Last post2021-12-18 12:11 -0300
Articles 20 on this page of 44 — 9 participants

Back to article view | Back to comp.lang.c


Contents

  on understanding & and pointer arithmetic Meredith Montgomery <mmontgomery@levado.to> - 2021-12-16 11:13 -0300
    Re: on understanding & and pointer arithmetic Bart <bc@freeuk.com> - 2021-12-16 14:23 +0000
      Re: on understanding & and pointer arithmetic Meredith Montgomery <mmontgomery@levado.to> - 2021-12-16 11:57 -0300
        Re: on understanding & and pointer arithmetic Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-12-16 17:42 +0000
          Re: on understanding & and pointer arithmetic Bart <bc@freeuk.com> - 2021-12-16 18:14 +0000
            Re: on understanding & and pointer arithmetic Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-12-16 21:14 +0000
          Re: on understanding & and pointer arithmetic Meredith Montgomery <mmontgomery@levado.to> - 2021-12-16 16:42 -0300
            Re: on understanding & and pointer arithmetic Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-16 12:44 -0800
              Re: on understanding & and pointer arithmetic Meredith Montgomery <mmontgomery@levado.to> - 2021-12-18 12:06 -0300
            Re: on understanding & and pointer arithmetic Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-12-16 21:34 +0000
              Re: on understanding & and pointer arithmetic Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-16 14:14 -0800
                Re: on understanding & and pointer arithmetic Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-12-16 23:44 +0000
              Re: on understanding & and pointer arithmetic Meredith Montgomery <mmontgomery@levado.to> - 2021-12-18 12:09 -0300
    Re: on understanding & and pointer arithmetic David Brown <david.brown@hesbynett.no> - 2021-12-16 16:23 +0100
      Re: on understanding & and pointer arithmetic Meredith Montgomery <mmontgomery@levado.to> - 2021-12-16 16:25 -0300
        Re: on understanding & and pointer arithmetic David Brown <david.brown@hesbynett.no> - 2021-12-16 21:08 +0100
          Re: on understanding & and pointer arithmetic Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-12-16 12:54 -0800
            Re: on understanding & and pointer arithmetic David Brown <david.brown@hesbynett.no> - 2021-12-17 10:53 +0100
              Re: on understanding & and pointer arithmetic Meredith Montgomery <mmontgomery@levado.to> - 2021-12-18 11:39 -0300
                Re: on understanding & and pointer arithmetic scott@slp53.sl.home (Scott Lurndal) - 2021-12-18 16:31 +0000
                Re: on understanding & and pointer arithmetic David Brown <david.brown@hesbynett.no> - 2021-12-18 18:56 +0100
                  Re: on understanding & and pointer arithmetic Meredith Montgomery <mmontgomery@levado.to> - 2021-12-25 21:29 -0300
                Re: on understanding & and pointer arithmetic Bart <bc@freeuk.com> - 2021-12-18 18:29 +0000
          Re: on understanding & and pointer arithmetic Meredith Montgomery <mmontgomery@levado.to> - 2021-12-18 11:32 -0300
      Re: on understanding & and pointer arithmetic Manfred <noname@add.invalid> - 2021-12-16 21:34 +0100
        Re: on understanding & and pointer arithmetic Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-12-16 22:20 +0000
          Re: on understanding & and pointer arithmetic Meredith Montgomery <mmontgomery@levado.to> - 2021-12-18 12:02 -0300
            Re: on understanding & and pointer arithmetic Meredith Montgomery <mmontgomery@levado.to> - 2021-12-18 12:34 -0300
            Re: on understanding & and pointer arithmetic Manfred <noname@add.invalid> - 2021-12-18 18:36 +0100
            Re: on understanding & and pointer arithmetic Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-12-18 21:17 +0000
        Re: on understanding & and pointer arithmetic James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-12-16 18:59 -0500
    Re: on understanding & and pointer arithmetic James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-12-16 18:38 -0500
      Re: on understanding & and pointer arithmetic Bart <bc@freeuk.com> - 2021-12-16 23:50 +0000
        Re: on understanding & and pointer arithmetic "james...@alumni.caltech.edu" <jameskuyper@alumni.caltech.edu> - 2021-12-17 07:34 -0800
          Re: on understanding & and pointer arithmetic Bart <bc@freeuk.com> - 2021-12-17 17:48 +0000
      Re: on understanding & and pointer arithmetic Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-12-16 23:56 +0000
        Re: on understanding & and pointer arithmetic James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-12-16 19:06 -0500
          Re: on understanding & and pointer arithmetic Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-12-17 00:10 +0000
          Re: on understanding & and pointer arithmetic Meredith Montgomery <mmontgomery@levado.to> - 2021-12-18 12:32 -0300
      Re: on understanding & and pointer arithmetic Meredith Montgomery <mmontgomery@levado.to> - 2021-12-18 12:30 -0300
    Re: on understanding & and pointer arithmetic David Brown <david.brown@hesbynett.no> - 2021-12-17 11:08 +0100
      Re: on understanding & and pointer arithmetic Manfred <noname@add.invalid> - 2021-12-17 16:24 +0100
        Re: on understanding & and pointer arithmetic David Brown <david.brown@hesbynett.no> - 2021-12-17 18:17 +0100
      Re: on understanding & and pointer arithmetic Meredith Montgomery <mmontgomery@levado.to> - 2021-12-18 12:11 -0300

Page 1 of 3  [1] 2 3  Next page →


#163857 — on understanding & and pointer arithmetic

FromMeredith Montgomery <mmontgomery@levado.to>
Date2021-12-16 11:13 -0300
Subjecton understanding & and pointer arithmetic
Message-ID<86a6h0eiy9.fsf@levado.to>
I'm investigating the syntax array[index] and I'm getting surprised at
some places.  My intuition says that a[3] is the same as a + 3.  I also
know that /&a/ is the same as /a/.  I first expected the following
program to print ``lo, world\n'' three times, but it does not.

--8<---------------cut here---------------start------------->8---
#include <stdio.h>
int main() {
  char a[] = "hello, world";
  printf("a: %s\n", &a[3]);
  printf("a: %s\n", a + 3);
  printf("a: %s\n", &a + 3);
}
--8<---------------cut here---------------end--------------->8---

%./hello.exe
a: lo, world
a: lo, world
a: ▒
%

I think part of my problem is a type-confusion I'm making.  The type of
a + 3 must still be (char *) while the third one must be some other
type?

I get the my-expected result this way:

--8<---------------cut here---------------start------------->8---
#include <stdio.h>
int main() {
  char a[] = "hello, world";
  printf("a: %s\n", &a[3]);
  printf("a: %s\n", a + 3);
  printf("a: %s\n", (char*) &a + 3);
}
--8<---------------cut here---------------end--------------->8---

So I think I must correct my intuition to remember that &var does not
produce a type ``char *''.  What does it produce?  Which reference could
I check to see an official statement of the fact?

My real request is --- can you educate me on this matter?  I don't think
I'm looking at things in the proper way.  For example, 

  printf("a: %s\n", (char*) (&a + 3));

produces the garbage I saw before.

Trying to see what's going on, I wrote

  printf("a: %p\n", a);
  printf("a: %p\n", a + 3);
  printf("a: %p\n", &a + 3);

and I got

--8<---------------cut here---------------start------------->8---
%./hello.exe
a: 0xffffcc33
a: 0xffffcc36
a: 0xffffcc5a
--8<---------------cut here---------------end--------------->8---

which illustrates my misunderstanding.  I expected the two last lines to
print ``a: 0xffffcc36'', but somehow ``&a + 3'' yields ``0xffffcc5a''
and not the 3 bytes further from 0xffffcc33 that I expected.

Thank you so much.

[toc] | [next] | [standalone]


#163859

FromBart <bc@freeuk.com>
Date2021-12-16 14:23 +0000
Message-ID<spfi5g$6ko$1@dont-email.me>
In reply to#163857
On 16/12/2021 14:13, Meredith Montgomery wrote:
> I'm investigating the syntax array[index] and I'm getting surprised at
> some places.  My intuition says that a[3] is the same as a + 3.

It's the same as *(a+3).

However if a is an array of arrays, then the array element at *(a+3) 
might decay to a pointer of that array, so it could end up as the same 
value as a+3, if different type:

     int a[5][4];

     printf("%p\n", a[3]);
     printf("%p\n", *(a+3));
     printf("%p\n", a+3);

These all show the same address. But change 'a' to 'int a[5]', and the 
first two lines show the value, the element a[3] (some random value if 
not initialised), and the last shows the address of that element.


> I also
> know that /&a/ is the same as /a/.

The same /what/? Those have the same values but different types ((T*)[] 
vs T* where T is a's element type).

[toc] | [prev] | [next] | [standalone]


#163861

FromMeredith Montgomery <mmontgomery@levado.to>
Date2021-12-16 11:57 -0300
Message-ID<865yrod2cx.fsf@levado.to>
In reply to#163859
Bart <bc@freeuk.com> writes:

> On 16/12/2021 14:13, Meredith Montgomery wrote:
>> I'm investigating the syntax array[index] and I'm getting surprised at
>> some places.  My intuition says that a[3] is the same as a + 3.
>
> It's the same as *(a+3).
>
> However if a is an array of arrays, then the array element at *(a+3)
> might decay to a pointer of that array, so it could end up as the same 
> value as a+3, if different type:
>
>     int a[5][4];
>
>     printf("%p\n", a[3]);
>     printf("%p\n", *(a+3));
>     printf("%p\n", a+3);
>
> These all show the same address. But change 'a' to 'int a[5]', and the
> first two lines show the value, the element a[3] (some random value if 
> not initialised), and the last shows the address of that element.

Point taken.  I have been considering just an array of characters, so
can we focus on this more restricted context?

>> I also
>> know that /&a/ is the same as /a/.
>
> The same /what/? Those have the same values but different types
> ((T*)[] vs T* where T is a's element type).

Oh, so that's at least part of what I didn't know.  I'm trying to use
this new information to explain the numbers, but I haven't made it yet.

--8<---------------cut here---------------start------------->8---
#include <stdio.h>
int main() {
  char a[] = "abc";
  printf("a: %lu\n", a);
  printf("a: %lu\n", a + 3);
  printf("a: %lu\n", &a + 3);
}
--8<---------------cut here---------------end--------------->8---

%./hello.exe
a: 4294954044
a: 4294954047
a: 4294954056
%

The array a is at 4294954044 and a + 3 is at 4294954047, as I expected.

Why is the third number at 4294954056?  This is 9 bytes to the right of
a.  Why 9 bytes?  I thought it could be 3 times the array size, but the
array size is 4 bytes (there's an ending '\0' in there) and not 3.  So
if that were the case, I'd answer 12 bytes to the right of /a/ and not 9
bytes.

Can you put me in the right track?  Thank you.

[toc] | [prev] | [next] | [standalone]


#163866

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2021-12-16 17:42 +0000
Message-ID<87h7b8wind.fsf@bsb.me.uk>
In reply to#163861
Meredith Montgomery <mmontgomery@levado.to> writes:

> Bart <bc@freeuk.com> writes:
>> On 16/12/2021 14:13, Meredith Montgomery wrote:

>>> I also
>>> know that /&a/ is the same as /a/.
>>
>> The same /what/? Those have the same values but different types
>> ((T*)[] vs T* where T is a's element type).

In this specific case, char (*)[4] and char *.  (T*)[] is not a valid
type (for some base type T), and even with the syntax corrected (it's
T(*)[]), it's still wrong because the size is missing.  C does have
array types with no size, but none are relevant to your case.

> Oh, so that's at least part of what I didn't know.  I'm trying to use
> this new information to explain the numbers, but I haven't made it
> yet.

Take care with Bart's replies.  He loves to make things sound more
complicated than then really are, and in this case the types he wrote
are wrong.  Also, pointer to array types are rarely used in C, so while
it's worth knowing about them, must people learn a lot of C before
coming across them.

> #include <stdio.h>
> int main() {
>   char a[] = "abc";
>   printf("a: %lu\n", a);
>   printf("a: %lu\n", a + 3);
>   printf("a: %lu\n", &a + 3);
> }

With any luck, you compiler should have had lots to say about this
code.  If it did not, turn up the warnings.  I'll write it my way with
comments.

#include <stdio.h>
int main(void) {  // Empty ()s here have a special, archaic, meaning.
  char a[] = "abc";
  // Declare a to be an array of 4 characters initialised with
  // 'a', 'b', 'c' and '\0'.
  printf("a: %p\n", (void *)a);
  // C has a format for pointers (%p), but you must convert the
  // pointer to the expected type of void *.
  printf("a: %p\n", (void *)(a + 3));
  printf("a: %p\n", (void *)(&a + 3));
}

> %./hello.exe
> a: 4294954044

This is the address of a -- the address of the first element.  Pointers
in C are addresses with type information.

> a: 4294954047

This is the address of the null at the end of the array.  An array name,
in most contexts, converts to a pointer to the first element, so a here
is of type char *.  Pointer arithmetic is done by adding units of the
size of the pointed-to type and, since sizeof(char) is 1, that adds
three.

> a: 4294954056

An array as the operand of & is one of very few cases where the
conversion to a pointer to the first element does not occur.  The result
is a pointer to the whole four-byte array.  Adding 3 therefore adds 3
times the size of that object, i.e. 12.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#163868

FromBart <bc@freeuk.com>
Date2021-12-16 18:14 +0000
Message-ID<spfvmh$9jq$1@dont-email.me>
In reply to#163866
On 16/12/2021 17:42, Ben Bacarisse wrote:
> Meredith Montgomery <mmontgomery@levado.to> writes:
> 
>> Bart <bc@freeuk.com> writes:
>>> On 16/12/2021 14:13, Meredith Montgomery wrote:
> 
>>>> I also
>>>> know that /&a/ is the same as /a/.
>>>
>>> The same /what/? Those have the same values but different types
>>> ((T*)[] vs T* where T is a's element type).
> 
> In this specific case, char (*)[4] and char *.  (T*)[] is not a valid
> type (for some base type T), and even with the syntax corrected (it's
> T(*)[]),

OK.

> it's still wrong because the size is missing.

When the OP wrote about a[3] at the top of the post, there was no 
declaration for 'a' and therefore no size. My remark applied to an array 
of any type.

And using [] generally means an array of any size.

(You can write a function taking T(*)[], and call it with T(*)[3] or 
T(*)[300].)

>> Oh, so that's at least part of what I didn't know.  I'm trying to use
>> this new information to explain the numbers, but I haven't made it
>> yet.
> 
> Take care with Bart's replies.  He loves to make things sound more
> complicated than then really are, and in this case the types he wrote
> are wrong.  Also, pointer to array types are rarely used in C, so while
> it's worth knowing about them,

Well, the OP mentioned &a, and that is its type.

[toc] | [prev] | [next] | [standalone]


#163883

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2021-12-16 21:14 +0000
Message-ID<8735msw8v3.fsf@bsb.me.uk>
In reply to#163868
Bart <bc@freeuk.com> writes:

> On 16/12/2021 17:42, Ben Bacarisse wrote:
>> Meredith Montgomery <mmontgomery@levado.to> writes:
>> 
>>> Bart <bc@freeuk.com> writes:
>>>> On 16/12/2021 14:13, Meredith Montgomery wrote:
>> 
>>>>> I also
>>>>> know that /&a/ is the same as /a/.
>>>>
>>>> The same /what/? Those have the same values but different types
>>>> ((T*)[] vs T* where T is a's element type).
>> In this specific case, char (*)[4] and char *.  (T*)[] is not a valid
>> type (for some base type T), and even with the syntax corrected (it's
>> T(*)[]),
>
> OK.
>
>> it's still wrong because the size is missing.
>
> When the OP wrote about a[3] at the top of the post, there was no
> declaration for 'a' and therefore no size. My remark applied to an
> array of any type.

That was an array access, not a declaration.  There was a declaration of
'a' in the post you replied to, but the type of &a in that context would
have been char (*)[13] as the initialiser was "hello, world".

> And using [] generally means an array of any size.

It actually means the array type is incomplete.  That means the array
has an unknown size.  I think "an array of any size" is too vague and
sounds more "useful" than incomplete array types really are.

> (You can write a function taking T(*)[], and call it with T(*)[3] or
> T(*)[300].)

Yes, a pointer to an incomplete array type is compatible with a pointer
to an array of a known size.

>>> Oh, so that's at least part of what I didn't know.  I'm trying to use
>>> this new information to explain the numbers, but I haven't made it
>>> yet.
>> Take care with Bart's replies.  He loves to make things sound more
>> complicated than then really are, and in this case the types he wrote
>> are wrong.  Also, pointer to array types are rarely used in C, so while
>> it's worth knowing about them,
>
> Well, the OP mentioned &a, and that is its type.

It's type was (in the post you were replying to) char (*)[13].  Giving
the wrong syntax for a pointer to an incomplete array type using "T" as
the element type was, to my, mind over-complicating the reply.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#163877

FromMeredith Montgomery <mmontgomery@levado.to>
Date2021-12-16 16:42 -0300
Message-ID<86ee6c9w1a.fsf@levado.to>
In reply to#163866
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:

> Meredith Montgomery <mmontgomery@levado.to> writes:
>
>> Bart <bc@freeuk.com> writes:
>>> On 16/12/2021 14:13, Meredith Montgomery wrote:
>
>>>> I also
>>>> know that /&a/ is the same as /a/.
>>>
>>> The same /what/? Those have the same values but different types
>>> ((T*)[] vs T* where T is a's element type).
>
> In this specific case, char (*)[4] and char *.  (T*)[] is not a valid
> type (for some base type T), and even with the syntax corrected (it's
> T(*)[]), it's still wrong because the size is missing.  C does have
> array types with no size, but none are relevant to your case.

Thanks for the correction.  I'll repeat what you say in my words just to
get a chance that you might verify what I'm saying.  When I have an
array such as 

  char a[] = "hello, world"

which occupies 13 bytes, then a pointer to it is a pointer of type

  char (*a)[13]

and that's how we write its type --- although I could omit the letter a
there, perhaps I should, I also think it's okay to write it there.  Bart
effectively wrote (char*)[], which is not the same or perhaps not a
valid type at all.  That's my understanding now.

>> Oh, so that's at least part of what I didn't know.  I'm trying to use
>> this new information to explain the numbers, but I haven't made it
>> yet.
>
> Take care with Bart's replies.  He loves to make things sound more
> complicated than then really are, and in this case the types he wrote
> are wrong.  Also, pointer to array types are rarely used in C, so while
> it's worth knowing about them, must people learn a lot of C before
> coming across them.

Thanks for the advice.  I'm still going to study declarations.  I do
think they're pretty difficult, but I believe they don't appear too
often.  Brian Kernighan says the same in the book.

>> #include <stdio.h>
>> int main() {
>>   char a[] = "abc";
>>   printf("a: %lu\n", a);
>>   printf("a: %lu\n", a + 3);
>>   printf("a: %lu\n", &a + 3);
>> }
>
> With any luck, you compiler should have had lots to say about this
> code.  If it did not, turn up the warnings.  I'll write it my way with
> comments.

Yes, the warnings were there.  In my new experiment I added casts, but
kept the %lu because I wanted to see things in base 10.

> #include <stdio.h>
> int main(void) {  // Empty ()s here have a special, archaic, meaning.
>   char a[] = "abc";
>   // Declare a to be an array of 4 characters initialised with
>   // 'a', 'b', 'c' and '\0'.
>   printf("a: %p\n", (void *)a);
>   // C has a format for pointers (%p), but you must convert the
>   // pointer to the expected type of void *.
>   printf("a: %p\n", (void *)(a + 3));
>   printf("a: %p\n", (void *)(&a + 3));
> }
>
>> %./hello.exe
>> a: 4294954044
>
> This is the address of a -- the address of the first element.  Pointers
> in C are addresses with type information.

That's good info!  I must keep this in mind --- addresses with type
information.  Thank you!

>> a: 4294954047
>
> This is the address of the null at the end of the array.  An array name,
> in most contexts, converts to a pointer to the first element, so a here
> is of type char *.  Pointer arithmetic is done by adding units of the
> size of the pointed-to type and, since sizeof(char) is 1, that adds
> three.
>
>> a: 4294954056
>
> An array as the operand of & is one of very few cases where the
> conversion to a pointer to the first element does not occur.  The result
> is a pointer to the whole four-byte array.  Adding 3 therefore adds 3
> times the size of that object, i.e. 12.

Thank you.  That's right --- I was expecting a conversion to a pointer
to the first element.  I'm much better prepared now.  Thanks a lot!

[toc] | [prev] | [next] | [standalone]


#163880

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2021-12-16 12:44 -0800
Message-ID<87ee6c8ekk.fsf@nosuchdomain.example.com>
In reply to#163877
Meredith Montgomery <mmontgomery@levado.to> writes:
[...]
> Thanks for the correction.  I'll repeat what you say in my words just to
> get a chance that you might verify what I'm saying.  When I have an
> array such as 
>
>   char a[] = "hello, world"
>
> which occupies 13 bytes, then a pointer to it is a pointer of type
>
>   char (*a)[13]
>
> and that's how we write its type --- although I could omit the letter a
> there, perhaps I should, I also think it's okay to write it there.  Bart
> effectively wrote (char*)[], which is not the same or perhaps not a
> valid type at all.  That's my understanding now.
[...]

The name "a" is not something you can arbitrarily decide to include or
omit.

`char (*)[13]` is a type name (pointer to array of 13 chars).

`char (*a)[13];` not a type name.  It's a declaration.  It declares an
object named `a` of type `char (*)[13]`.  (And it needs that trailing
semicolon.)

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#163951

FromMeredith Montgomery <mmontgomery@levado.to>
Date2021-12-18 12:06 -0300
Message-ID<86h7b66jh9.fsf@levado.to>
In reply to#163880
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

> Meredith Montgomery <mmontgomery@levado.to> writes:
> [...]
>> Thanks for the correction.  I'll repeat what you say in my words just to
>> get a chance that you might verify what I'm saying.  When I have an
>> array such as 
>>
>>   char a[] = "hello, world"
>>
>> which occupies 13 bytes, then a pointer to it is a pointer of type
>>
>>   char (*a)[13]
>>
>> and that's how we write its type --- although I could omit the letter a
>> there, perhaps I should, I also think it's okay to write it there.  Bart
>> effectively wrote (char*)[], which is not the same or perhaps not a
>> valid type at all.  That's my understanding now.
> [...]
>
> The name "a" is not something you can arbitrarily decide to include or
> omit.
>
> `char (*)[13]` is a type name (pointer to array of 13 chars).
>
> `char (*a)[13];` not a type name.  It's a declaration.  It declares an
> object named `a` of type `char (*)[13]`.  (And it needs that trailing
> semicolon.)

Understood.  Thanks!

[toc] | [prev] | [next] | [standalone]


#163885

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2021-12-16 21:34 +0000
Message-ID<87wnk4utcs.fsf@bsb.me.uk>
In reply to#163877
Meredith Montgomery <mmontgomery@levado.to> writes:

> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>
>> Meredith Montgomery <mmontgomery@levado.to> writes:
>>
>>> Bart <bc@freeuk.com> writes:
>>>> On 16/12/2021 14:13, Meredith Montgomery wrote:
>>
>>>>> I also
>>>>> know that /&a/ is the same as /a/.
>>>>
>>>> The same /what/? Those have the same values but different types
>>>> ((T*)[] vs T* where T is a's element type).
>>
>> In this specific case, char (*)[4] and char *.  (T*)[] is not a valid
>> type (for some base type T), and even with the syntax corrected (it's
>> T(*)[]), it's still wrong because the size is missing.  C does have
>> array types with no size, but none are relevant to your case.
>
> Thanks for the correction.  I'll repeat what you say in my words just to
> get a chance that you might verify what I'm saying.  When I have an
> array such as 
>
>   char a[] = "hello, world"
>
> which occupies 13 bytes, then a pointer to it is a pointer of type
>
>   char (*a)[13]
>
> and that's how we write its type --- although I could omit the letter a
> there, perhaps I should, I also think it's okay to write it there.

Not quite.  When you write a type (for example, to use in a cast
operator) you must omit the name.  If you include a name, then what you
are writing a declaration, not a type.

So, the object `a` has type char [13].  When used in a most contexts,
`a` is converted to an expression of type char *, but when you apply the
& operator, this conversion is not done and the pointer you get is of
type char (*)[13].

> Bart
> effectively wrote (char*)[], which is not the same or perhaps not a
> valid type at all.  That's my understanding now.

Yes, that was just (I assume) a typo.  Bart knows how to write pointer-
to-array types because his software uses them more than most C code
does.  But the empty [] are wrong here.  Your [13] is correct.

<cut>
>>> #include <stdio.h>
>>> int main() {
>>>   char a[] = "abc";
>>>   printf("a: %lu\n", a);
>>>   printf("a: %lu\n", a + 3);
>>>   printf("a: %lu\n", &a + 3);
>>> }
>>
>> With any luck, you compiler should have had lots to say about this
>> code.  If it did not, turn up the warnings.  I'll write it my way with
>> comments.
>
> Yes, the warnings were there.  In my new experiment I added casts, but
> kept the %lu because I wanted to see things in base 10.

OK, so you converted the pointers to unsigned long.  That will often
work, but "modern" C (since 1999), has an integer type that, if the
conversion is possible at all, is guaranteed to be the right width:
uintptr_t.  It, along with a whole lot of other useful types, is
declared in <stdint.h>.

You might ask, how does one print such a type?  Well there is another
header, <inttypes.h>, that defines macros with the right width:

  printf("a is at %"PRIuPTR"\n", (uintptr_t)a);

A bit of a mouthful, but the result will work on any system where
pointers can be converted to some unsigned integer type.  (There is also
a signed integer type intptr_t and a corresponding macro, PRIiPTR, for
printing it.)

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#163888

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2021-12-16 14:14 -0800
Message-ID<875yro8afq.fsf@nosuchdomain.example.com>
In reply to#163885
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
> Meredith Montgomery <mmontgomery@levado.to> writes:
>> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>>> Meredith Montgomery <mmontgomery@levado.to> writes:
[...]
>>>> #include <stdio.h>
>>>> int main() {
>>>>   char a[] = "abc";
>>>>   printf("a: %lu\n", a);
>>>>   printf("a: %lu\n", a + 3);
>>>>   printf("a: %lu\n", &a + 3);
>>>> }
>>>
>>> With any luck, you compiler should have had lots to say about this
>>> code.  If it did not, turn up the warnings.  I'll write it my way with
>>> comments.
>>
>> Yes, the warnings were there.  In my new experiment I added casts, but
>> kept the %lu because I wanted to see things in base 10.
>
> OK, so you converted the pointers to unsigned long.  That will often
> work, but "modern" C (since 1999), has an integer type that, if the
> conversion is possible at all, is guaranteed to be the right width:
> uintptr_t.  It, along with a whole lot of other useful types, is
> declared in <stdint.h>.
>
> You might ask, how does one print such a type?  Well there is another
> header, <inttypes.h>, that defines macros with the right width:
>
>   printf("a is at %"PRIuPTR"\n", (uintptr_t)a);
>
> A bit of a mouthful, but the result will work on any system where
> pointers can be converted to some unsigned integer type.  (There is also
> a signed integer type intptr_t and a corresponding macro, PRIiPTR, for
> printing it.)

Yes, but the usual way to print pointer values is to cast to void* and
use "%p".

The "%p" format produces a string that represents a pointer value in
some implementation-defined manner (hexadecimal is common).  (Bart
mentioned this upthread.)

You can convert to uintptr_t and use %"PRIuPTR" if (a) you specifically
want decimal output for some reason and (b) you don't mind a slight loss
of portability (it can fail for pre-C99 implementations and for rare
implementations that don't have an integer type big enough to hold a
pointer value).

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#163892

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2021-12-16 23:44 +0000
Message-ID<87pmpwt8rp.fsf@bsb.me.uk>
In reply to#163888
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:

> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>> Meredith Montgomery <mmontgomery@levado.to> writes:
>>> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>>>> Meredith Montgomery <mmontgomery@levado.to> writes:
> [...]
>>>>> #include <stdio.h>
>>>>> int main() {
>>>>>   char a[] = "abc";
>>>>>   printf("a: %lu\n", a);
>>>>>   printf("a: %lu\n", a + 3);
>>>>>   printf("a: %lu\n", &a + 3);
>>>>> }
>>>>
>>>> With any luck, you compiler should have had lots to say about this
>>>> code.  If it did not, turn up the warnings.  I'll write it my way with
>>>> comments.
>>>
>>> Yes, the warnings were there.  In my new experiment I added casts, but
>>> kept the %lu because I wanted to see things in base 10.
>>
>> OK, so you converted the pointers to unsigned long.  That will often
>> work, but "modern" C (since 1999), has an integer type that, if the
>> conversion is possible at all, is guaranteed to be the right width:
>> uintptr_t.  It, along with a whole lot of other useful types, is
>> declared in <stdint.h>.
>>
>> You might ask, how does one print such a type?  Well there is another
>> header, <inttypes.h>, that defines macros with the right width:
>>
>>   printf("a is at %"PRIuPTR"\n", (uintptr_t)a);
>>
>> A bit of a mouthful, but the result will work on any system where
>> pointers can be converted to some unsigned integer type.  (There is also
>> a signed integer type intptr_t and a corresponding macro, PRIiPTR, for
>> printing it.)
>
> Yes, but the usual way to print pointer values is to cast to void* and
> use "%p".

Yes, I wrote that out for the OP in my very first reply.

> You can convert to uintptr_t and use %"PRIuPTR" if (a) you specifically
> want decimal output for some reason

Later, the OP said they /did/ want to see decimal (presumably to make
the arithmetic even clearer) so I explained how to do that.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#163952

FromMeredith Montgomery <mmontgomery@levado.to>
Date2021-12-18 12:09 -0300
Message-ID<867dc26jce.fsf@levado.to>
In reply to#163885
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:

> Meredith Montgomery <mmontgomery@levado.to> writes:
>
>> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>>
>>> Meredith Montgomery <mmontgomery@levado.to> writes:
>>>
>>>> Bart <bc@freeuk.com> writes:
>>>>> On 16/12/2021 14:13, Meredith Montgomery wrote:
>>>
>>>>>> I also
>>>>>> know that /&a/ is the same as /a/.
>>>>>
>>>>> The same /what/? Those have the same values but different types
>>>>> ((T*)[] vs T* where T is a's element type).
>>>
>>> In this specific case, char (*)[4] and char *.  (T*)[] is not a valid
>>> type (for some base type T), and even with the syntax corrected (it's
>>> T(*)[]), it's still wrong because the size is missing.  C does have
>>> array types with no size, but none are relevant to your case.
>>
>> Thanks for the correction.  I'll repeat what you say in my words just to
>> get a chance that you might verify what I'm saying.  When I have an
>> array such as 
>>
>>   char a[] = "hello, world"
>>
>> which occupies 13 bytes, then a pointer to it is a pointer of type
>>
>>   char (*a)[13]
>>
>> and that's how we write its type --- although I could omit the letter a
>> there, perhaps I should, I also think it's okay to write it there.
>
> Not quite.  When you write a type (for example, to use in a cast
> operator) you must omit the name.  If you include a name, then what you
> are writing a declaration, not a type.
>
> So, the object `a` has type char [13].  When used in a most contexts,
> `a` is converted to an expression of type char *, but when you apply the
> & operator, this conversion is not done and the pointer you get is of
> type char (*)[13].

Understood.

[...]

>>>> #include <stdio.h>
>>>> int main() {
>>>>   char a[] = "abc";
>>>>   printf("a: %lu\n", a);
>>>>   printf("a: %lu\n", a + 3);
>>>>   printf("a: %lu\n", &a + 3);
>>>> }
>>>
>>> With any luck, you compiler should have had lots to say about this
>>> code.  If it did not, turn up the warnings.  I'll write it my way with
>>> comments.
>>
>> Yes, the warnings were there.  In my new experiment I added casts, but
>> kept the %lu because I wanted to see things in base 10.
>
> OK, so you converted the pointers to unsigned long.  That will often
> work, but "modern" C (since 1999), has an integer type that, if the
> conversion is possible at all, is guaranteed to be the right width:
> uintptr_t.  It, along with a whole lot of other useful types, is
> declared in <stdint.h>.
>
> You might ask, how does one print such a type?  Well there is another
> header, <inttypes.h>, that defines macros with the right width:
>
>   printf("a is at %"PRIuPTR"\n", (uintptr_t)a);
>
> A bit of a mouthful, but the result will work on any system where
> pointers can be converted to some unsigned integer type.  (There is also
> a signed integer type intptr_t and a corresponding macro, PRIiPTR, for
> printing it.)

Thanks.  Not long ago, I think I myself initiated some thread where I
learned about these PRI* constants for printf and where to find
documentation for them.  But the uintptr_t is new to me.  Thanks for the
info.

[toc] | [prev] | [next] | [standalone]


#163862

FromDavid Brown <david.brown@hesbynett.no>
Date2021-12-16 16:23 +0100
Message-ID<spfllt$vkn$1@dont-email.me>
In reply to#163857
On 16/12/2021 15:13, Meredith Montgomery wrote:
> I'm investigating the syntax array[index] and I'm getting surprised at
> some places.  My intuition says that a[3] is the same as a + 3.  I also
> know that /&a/ is the same as /a/.  I first expected the following
> program to print ``lo, world\n'' three times, but it does not.

I can see why you are confused - you are close, but a bit mixed up.

"a[3]" is the same as "*(a + 3)".  The dereferencing is crucial.

In the code below, "a" is an array of 13 char - and that is its type.
When you take its address, "&a", you have a pointer to an array of 13
char.  This will have the same /value/ as &a[0], which is a pointer to
the first element of the array - a pointer to a char.

In many expressions (apart from "sizeof a" or "&a"), "a" will decay to a
pointer to its first element.  That is, the "array of char" is turned
into a "pointer to char".  And this pointer will have the same /value/
as &a[0], and therefore as &a.  But it is not the same thing, even when
used in an expression - types are very important.

> 
> --8<---------------cut here---------------start------------->8---
> #include <stdio.h>
> int main() {
>   char a[] = "hello, world";
>   printf("a: %s\n", &a[3]);

&a[3] is the address of element 3 (i.e., the fourth letter) of the array
"a".

>   printf("a: %s\n", a + 3);

"a" here gets converted to a  pointer to the first element, and then 3
elements are added - giving a pointer to a char at the address of element 3.

>   printf("a: %s\n", &a + 3);

"a" here is the full array, so "&a" is a pointer to an array of 13 char.
 Adding 3 gives a new pointer to an array of 13 char, at the address 39
bytes higher than address of "a".  Basically, you are pretending that
there is an array of 4 elements, each of which is itself an array of 13
chars - with "a" being the first of those 4 elements.  Now you are
asking to print the 4th element here, which is just whatever happens to
be in the memory at that address.

> }
> --8<---------------cut here---------------end--------------->8---
> 
> %./hello.exe
> a: lo, world
> a: lo, world
> a: ▒
> %
> 
> I think part of my problem is a type-confusion I'm making.  The type of
> a + 3 must still be (char *) while the third one must be some other
> type?

Yes.  Understanding the source of your confusion is the first step
towards resolving it.

> 
> I get the my-expected result this way:
> 
> --8<---------------cut here---------------start------------->8---
> #include <stdio.h>
> int main() {
>   char a[] = "hello, world";
>   printf("a: %s\n", &a[3]);
>   printf("a: %s\n", a + 3);
>   printf("a: %s\n", (char*) &a + 3);
> }
> --8<---------------cut here---------------end--------------->8---
> 
> So I think I must correct my intuition to remember that &var does not
> produce a type ``char *''.  What does it produce?  Which reference could
> I check to see an official statement of the fact?

For a good reference, I like "en.cppreference.com".  Here are some
relevant pages:

<https://en.cppreference.com/w/c/language/conversion>
<https://en.cppreference.com/w/c/language/operator_member_access>
<https://en.cppreference.com/w/c/language/array>

That site is an easier reference than reading the standards.  But it is
still a reference - you may want a tutorial page rather than a reference.


> 
> My real request is --- can you educate me on this matter?  I don't think
> I'm looking at things in the proper way.  For example, 
> 
>   printf("a: %s\n", (char*) (&a + 3));
> 
> produces the garbage I saw before.
> 
> Trying to see what's going on, I wrote
> 
>   printf("a: %p\n", a);
>   printf("a: %p\n", a + 3);
>   printf("a: %p\n", &a + 3);
> 
> and I got
> 
> --8<---------------cut here---------------start------------->8---
> %./hello.exe
> a: 0xffffcc33
> a: 0xffffcc36
> a: 0xffffcc5a
> --8<---------------cut here---------------end--------------->8---
> 
> which illustrates my misunderstanding.  I expected the two last lines to
> print ``a: 0xffffcc36'', but somehow ``&a + 3'' yields ``0xffffcc5a''
> and not the 3 bytes further from 0xffffcc33 that I expected.
> 
> Thank you so much.
> 

I think you should be able to figure this out now, given what I wrote
earlier.

[toc] | [prev] | [next] | [standalone]


#163875

FromMeredith Montgomery <mmontgomery@levado.to>
Date2021-12-16 16:25 -0300
Message-ID<8635msbbcu.fsf@levado.to>
In reply to#163862
David Brown <david.brown@hesbynett.no> writes:

> On 16/12/2021 15:13, Meredith Montgomery wrote:
>> I'm investigating the syntax array[index] and I'm getting surprised at
>> some places.  My intuition says that a[3] is the same as a + 3.  I also
>> know that /&a/ is the same as /a/.  I first expected the following
>> program to print ``lo, world\n'' three times, but it does not.
>
> I can see why you are confused - you are close, but a bit mixed up.
>
> "a[3]" is the same as "*(a + 3)".  The dereferencing is crucial.

Thank you!

> In the code below, "a" is an array of 13 char - and that is its type.
> When you take its address, "&a", you have a pointer to an array of 13
> char.  This will have the same /value/ as &a[0], which is a pointer to
> the first element of the array - a pointer to a char.

Yes, so that corrects me at least once.  I didn't think &a would be of a
different type.  So the type of &a is array of 13 char.  I get that.
The value of &a is the same /value/ as &a[0].  I also get that.  I'm
good here.

> In many expressions (apart from "sizeof a" or "&a"), "a" will decay to a
> pointer to its first element.  That is, the "array of char" is turned
> into a "pointer to char".  And this pointer will have the same /value/
> as &a[0], and therefore as &a.  But it is not the same thing, even when
> used in an expression - types are very important.

Alright, I got it now.  The types change, but the values are the same.
So all care must taken precisely when pointer arithmetic is used because
the types are totally determinant there.

>> --8<---------------cut here---------------start------------->8---
>> #include <stdio.h>
>> int main() {
>>   char a[] = "hello, world";
>>   printf("a: %s\n", &a[3]);
>
> &a[3] is the address of element 3 (i.e., the fourth letter) of the array
> "a".
>
>>   printf("a: %s\n", a + 3);
>
> "a" here gets converted to a  pointer to the first element, and then 3
> elements are added - giving a pointer to a char at the address of element 3.

I'm good there too.

>>   printf("a: %s\n", &a + 3);
>
> "a" here is the full array, so "&a" is a pointer to an array of 13 char.
>  Adding 3 gives a new pointer to an array of 13 char, at the address 39
> bytes higher than address of "a".  Basically, you are pretending that
> there is an array of 4 elements, each of which is itself an array of 13
> chars - with "a" being the first of those 4 elements.  Now you are
> asking to print the 4th element here, which is just whatever happens to
> be in the memory at that address.

Let me do the arithmetic and see if I get the same thing.  Since &a is a
pointer to an array of 13 char, then I would say that

  &a + 1 

should jump 13 bytes ``to the right'' because that is the size of the
array to which &a points to.  That appears to be the case.  The 39
bytes, therefore, is due to 13 * 3.

Confirming that:

--8<---------------cut here---------------start------------->8---
#include <stdio.h>
int main(void) {
  char a[] = "hello, world";
  printf("%lu\n", (unsigned long) a);
  printf("%lu\n", (unsigned long) &a);
  printf("%lu\n", (unsigned long) (&a + 1));
  printf("Jumped %lu bytes to the right\n", 
         (unsigned long) (&a + 1) - (unsigned long) &a);
  printf("%lu\n", (unsigned long) (&a + 3));
  printf("Jumped %lu bytes to the right\n", 
         (unsigned long) (&a + 3) - (unsigned long) &a);
}
--8<---------------cut here---------------end--------------->8---

%./arr
4294954035
4294954035
4294954048
Jumped 13 bytes to the right
4294954074
Jumped 39 bytes to the right
%

If that's indeed right, then things are falling into place now.  Thank
you so much, David!  As always, I'm very grateful!

By the way, I'm using (unsigned long) and %lu because I wanted the
numbers in base 10 for an easier arithmetic life.
 
>> %./hello.exe
>> a: lo, world
>> a: lo, world
>> a: ▒
>> %
>> 
>> I think part of my problem is a type-confusion I'm making.  The type of
>> a + 3 must still be (char *) while the third one must be some other
>> type?
>
> Yes.  Understanding the source of your confusion is the first step
> towards resolving it.

If I'm not there yet, I should be close because things seem to be
working as I now expect.

[...]

> I think you should be able to figure this out now, given what I wrote
> earlier.

I think that I did.  Very grateful!

[toc] | [prev] | [next] | [standalone]


#163878

FromDavid Brown <david.brown@hesbynett.no>
Date2021-12-16 21:08 +0100
Message-ID<spg6b8$on0$1@dont-email.me>
In reply to#163875
On 16/12/2021 20:25, Meredith Montgomery wrote:
> David Brown <david.brown@hesbynett.no> writes:
> 
>> On 16/12/2021 15:13, Meredith Montgomery wrote:
>>> I'm investigating the syntax array[index] and I'm getting surprised at
>>> some places.  My intuition says that a[3] is the same as a + 3.  I also
>>> know that /&a/ is the same as /a/.  I first expected the following
>>> program to print ``lo, world\n'' three times, but it does not.
>>
>> I can see why you are confused - you are close, but a bit mixed up.
>>
>> "a[3]" is the same as "*(a + 3)".  The dereferencing is crucial.
> 
> Thank you!
> 
>> In the code below, "a" is an array of 13 char - and that is its type.
>> When you take its address, "&a", you have a pointer to an array of 13
>> char.  This will have the same /value/ as &a[0], which is a pointer to
>> the first element of the array - a pointer to a char.
> 
> Yes, so that corrects me at least once.  I didn't think &a would be of a
> different type.  So the type of &a is array of 13 char.  I get that.

/No/.  "a" is of type "array of 13 char".  "&a" is of type "pointer to
array of 13 char".  These are different.

> The value of &a is the same /value/ as &a[0].  I also get that.  I'm
> good here.

Correct.  As Ben said (and Ben is very good at explaining things
accurately), a pointer has a type and has an address as it's value.  So
the values of pointers here are the same, but the pointers themselves
are different because they have different types.

> 
>> In many expressions (apart from "sizeof a" or "&a"), "a" will decay to a
>> pointer to its first element.  That is, the "array of char" is turned
>> into a "pointer to char".  And this pointer will have the same /value/
>> as &a[0], and therefore as &a.  But it is not the same thing, even when
>> used in an expression - types are very important.
> 
> Alright, I got it now.  The types change, but the values are the same.
> So all care must taken precisely when pointer arithmetic is used because
> the types are totally determinant there.

Yes.  Once you get used to the way array identifiers are converted into
pointers, it all works naturally and easily.

> 
>>> --8<---------------cut here---------------start------------->8---
>>> #include <stdio.h>
>>> int main() {
>>>   char a[] = "hello, world";
>>>   printf("a: %s\n", &a[3]);
>>
>> &a[3] is the address of element 3 (i.e., the fourth letter) of the array
>> "a".
>>
>>>   printf("a: %s\n", a + 3);
>>
>> "a" here gets converted to a  pointer to the first element, and then 3
>> elements are added - giving a pointer to a char at the address of element 3.
> 
> I'm good there too.
> 
>>>   printf("a: %s\n", &a + 3);
>>
>> "a" here is the full array, so "&a" is a pointer to an array of 13 char.
>>  Adding 3 gives a new pointer to an array of 13 char, at the address 39
>> bytes higher than address of "a".  Basically, you are pretending that
>> there is an array of 4 elements, each of which is itself an array of 13
>> chars - with "a" being the first of those 4 elements.  Now you are
>> asking to print the 4th element here, which is just whatever happens to
>> be in the memory at that address.
> 
> Let me do the arithmetic and see if I get the same thing.  Since &a is a
> pointer to an array of 13 char, then I would say that
> 
>   &a + 1 
> 
> should jump 13 bytes ``to the right'' because that is the size of the
> array to which &a points to.  That appears to be the case.  The 39
> bytes, therefore, is due to 13 * 3.
> 

Yes.

> Confirming that:
> 
> --8<---------------cut here---------------start------------->8---
> #include <stdio.h>
> int main(void) {
>   char a[] = "hello, world";
>   printf("%lu\n", (unsigned long) a);
>   printf("%lu\n", (unsigned long) &a);
>   printf("%lu\n", (unsigned long) (&a + 1));
>   printf("Jumped %lu bytes to the right\n", 
>          (unsigned long) (&a + 1) - (unsigned long) &a);
>   printf("%lu\n", (unsigned long) (&a + 3));
>   printf("Jumped %lu bytes to the right\n", 
>          (unsigned long) (&a + 3) - (unsigned long) &a);
> }
> --8<---------------cut here---------------end--------------->8---
> 
> %./arr
> 4294954035
> 4294954035
> 4294954048
> Jumped 13 bytes to the right
> 4294954074
> Jumped 39 bytes to the right
> %
> 
> If that's indeed right, then things are falling into place now.  Thank
> you so much, David!  As always, I'm very grateful!
> 
> By the way, I'm using (unsigned long) and %lu because I wanted the
> numbers in base 10 for an easier arithmetic life.
>  
>>> %./hello.exe
>>> a: lo, world
>>> a: lo, world
>>> a: ▒
>>> %
>>>
>>> I think part of my problem is a type-confusion I'm making.  The type of
>>> a + 3 must still be (char *) while the third one must be some other
>>> type?
>>
>> Yes.  Understanding the source of your confusion is the first step
>> towards resolving it.
> 
> If I'm not there yet, I should be close because things seem to be
> working as I now expect.
> 
> [...]
> 
>> I think you should be able to figure this out now, given what I wrote
>> earlier.
> 
> I think that I did.  Very grateful!
> 


Once you feel you have got the hang of this, repeat the whole thing with
an array of "int" rather than an array of "char".  That will help you
appreciate where the scalings come in.  (Note that while an "int" is 4
bytes, or 4 chars, on your platform, it is not necessarily the case on
other C implementations, especially for very small devices.)

[toc] | [prev] | [next] | [standalone]


#163882

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2021-12-16 12:54 -0800
Message-ID<87a6h08e4a.fsf@nosuchdomain.example.com>
In reply to#163878
David Brown <david.brown@hesbynett.no> writes:
> On 16/12/2021 20:25, Meredith Montgomery wrote:
[...]
>> Yes, so that corrects me at least once.  I didn't think &a would be of a
>> different type.  So the type of &a is array of 13 char.  I get that.
>
> /No/.  "a" is of type "array of 13 char".  "&a" is of type "pointer to
> array of 13 char".  These are different.
>
>> The value of &a is the same /value/ as &a[0].  I also get that.  I'm
>> good here.
>
> Correct.  As Ben said (and Ben is very good at explaining things
> accurately), a pointer has a type and has an address as it's value.  So
> the values of pointers here are the same, but the pointers themselves
> are different because they have different types.

I don't think I'd say that &a and &a[0] have the same *value*, though it
depends on just what you mean by "value".

They refer to the same location in memory, so that `(void*)&a` and
`(void*)&a[0]` do have the same value.  But they're of different types,
and a "value" in C includes its type.  This can get a bit vague at
times, and it's common to handwave away the difference, even in the
standard.  It can be particularly vague when were talking about numeric
values; are 3, 3U, and 3.0 the same value?

Note that `&a == &a[0]` is a constraint violation, in case you were
thinking that "same value" can be defined in terms of equality.

For pointers of different types, I suggest avoiding the issue by saying
that they refer to the same location.

The standard's definition of "value" (N1570 3.19) is:

    precise meaning of the contents of an object when interpreted as
    having a specific type

That definition is incomplete, since it excludes a "value" that results
from evaluation an expression.  `2+2` has a value (spoiler: it's 4), but
that value is not the contents of any object.

[...]

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#163907

FromDavid Brown <david.brown@hesbynett.no>
Date2021-12-17 10:53 +0100
Message-ID<sphmnl$vuo$1@dont-email.me>
In reply to#163882
On 16/12/2021 21:54, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
>> On 16/12/2021 20:25, Meredith Montgomery wrote:
> [...]
>>> Yes, so that corrects me at least once.  I didn't think &a would be of a
>>> different type.  So the type of &a is array of 13 char.  I get that.
>>
>> /No/.  "a" is of type "array of 13 char".  "&a" is of type "pointer to
>> array of 13 char".  These are different.
>>
>>> The value of &a is the same /value/ as &a[0].  I also get that.  I'm
>>> good here.
>>
>> Correct.  As Ben said (and Ben is very good at explaining things
>> accurately), a pointer has a type and has an address as it's value.  So
>> the values of pointers here are the same, but the pointers themselves
>> are different because they have different types.
> 
> I don't think I'd say that &a and &a[0] have the same *value*, though it
> depends on just what you mean by "value".

Yes, indeed it does.  As always in threads like these, there is a
balance to be found between trying to have approximate explanations and
terms that are easier for the relative beginner OP, and trying to be as
accurate as possible with precise terms to help the OP get the details
right from the start (and of course there are always other people
reading the thread, who might benefit from more insight).

Objects in C always have a type, and they contain some sort of data -
which can reasonably be called its "value".  For pointers, that will be
the address they contain - the value the OP is getting when he casts
these to an unsigned long and prints them out.

I know the real picture can be more complicated - different pointer
types can have different sizes, pointers can contain more than just an
address or memory location, two pointers of different types might
contain the same raw value but refer to different address spaces, they
might contain different raw values but refer to the same location and
may or may not compare equal, there can be trap representations, etc.
(That list is not complete.)  So what I am writing is "lies to
children", rather than trying to be complete and precise (partly because
others here, such as yourself, are significantly better at that kind of
answer).  If you are not familiar with the specific phrase "lies to
children", ask Santa for "The Science of the Discworld" :-)

> 
> They refer to the same location in memory, so that `(void*)&a` and
> `(void*)&a[0]` do have the same value.  But they're of different types,
> and a "value" in C includes its type.  This can get a bit vague at
> times, and it's common to handwave away the difference, even in the
> standard.  It can be particularly vague when were talking about numeric
> values; are 3, 3U, and 3.0 the same value?
> 
> Note that `&a == &a[0]` is a constraint violation, in case you were
> thinking that "same value" can be defined in terms of equality.
> 
> For pointers of different types, I suggest avoiding the issue by saying
> that they refer to the same location.

That might have been a better way to express it.

> 
> The standard's definition of "value" (N1570 3.19) is:
> 
>     precise meaning of the contents of an object when interpreted as
>     having a specific type
> 
> That definition is incomplete, since it excludes a "value" that results
> from evaluation an expression.  `2+2` has a value (spoiler: it's 4), but
> that value is not the contents of any object.
> 

Lots of the standard's definitions can be a bit vague or incomplete, or
refer to other terms that are not defined - ultimately it is necessary
to rely on common sense or common programming concepts at some point.

[toc] | [prev] | [next] | [standalone]


#163947

FromMeredith Montgomery <mmontgomery@levado.to>
Date2021-12-18 11:39 -0300
Message-ID<86czlu7zap.fsf@levado.to>
In reply to#163907
David Brown <david.brown@hesbynett.no> writes:

> On 16/12/2021 21:54, Keith Thompson wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>>> On 16/12/2021 20:25, Meredith Montgomery wrote:
>> [...]
>>>> Yes, so that corrects me at least once.  I didn't think &a would be of a
>>>> different type.  So the type of &a is array of 13 char.  I get that.
>>>
>>> /No/.  "a" is of type "array of 13 char".  "&a" is of type "pointer to
>>> array of 13 char".  These are different.
>>>
>>>> The value of &a is the same /value/ as &a[0].  I also get that.  I'm
>>>> good here.
>>>
>>> Correct.  As Ben said (and Ben is very good at explaining things
>>> accurately), a pointer has a type and has an address as it's value.  So
>>> the values of pointers here are the same, but the pointers themselves
>>> are different because they have different types.
>> 
>> I don't think I'd say that &a and &a[0] have the same *value*, though it
>> depends on just what you mean by "value".
>
> Yes, indeed it does.  As always in threads like these, there is a
> balance to be found between trying to have approximate explanations and
> terms that are easier for the relative beginner OP, and trying to be as
> accurate as possible with precise terms to help the OP get the details
> right from the start (and of course there are always other people
> reading the thread, who might benefit from more insight).
>
> Objects in C always have a type, and they contain some sort of data -
> which can reasonably be called its "value".  For pointers, that will be
> the address they contain - the value the OP is getting when he casts
> these to an unsigned long and prints them out.
>
> I know the real picture can be more complicated - different pointer
> types can have different sizes, pointers can contain more than just an
> address or memory location, two pointers of different types might
> contain the same raw value but refer to different address spaces, they
> might contain different raw values but refer to the same location and
> may or may not compare equal, there can be trap representations, etc.
> (That list is not complete.)  So what I am writing is "lies to
> children", rather than trying to be complete and precise (partly because
> others here, such as yourself, are significantly better at that kind of
> answer).  If you are not familiar with the specific phrase "lies to
> children", ask Santa for "The Science of the Discworld" :-)

For the record, I enjoyed the simplicity of this (sub)thread.  I was
trying to understand why my expectation was wrong.  So, I was already in
some trouble; bringing in more details at that point would not have
helped more than not bringing them in.

It's also nice to see that the situation is even deeper than I would
have thought, though.  For instance, right now my intuition is that the
size of a pointer on a 64-bit machine is always 8 bytes.  Can anyone
show an easy example of when this isn't true?

[...]

[toc] | [prev] | [next] | [standalone]


#163962

Fromscott@slp53.sl.home (Scott Lurndal)
Date2021-12-18 16:31 +0000
Message-ID<g1ovJ.110305$lz3.67826@fx34.iad>
In reply to#163947
Meredith Montgomery <mmontgomery@levado.to> writes:
>David Brown <david.brown@hesbynett.no> writes:
>

>>
>> I know the real picture can be more complicated - different pointer
>> types can have different sizes, pointers can contain more than just an
>> address or memory location, two pointers of different types might
>> contain the same raw value but refer to different address spaces, they
>> might contain different raw values but refer to the same location and
>> may or may not compare equal, there can be trap representations, etc.
>> (That list is not complete.)  So what I am writing is "lies to
>> children", rather than trying to be complete and precise (partly because
>> others here, such as yourself, are significantly better at that kind of
>> answer).  If you are not familiar with the specific phrase "lies to
>> children", ask Santa for "The Science of the Discworld" :-)
>
 [snip]
>It's also nice to see that the situation is even deeper than I would
>have thought, though.  For instance, right now my intuition is that the
>size of a pointer on a 64-bit machine is always 8 bytes.  Can anyone
>show an easy example of when this isn't true?

That statement may be considered true for the current generation
of general purpose hardware, albeit dependent upon your definition
of 64-bit machine as supporting a 64-bit address on its bus/mesh/ring.

A system may support 64-bit arithmetic natively without supporing
more than a 32-bit address space, particularly in harvard-style
architectures.

There are systems under design right now that have 128-bit pointers,
yet only support a 64-bit address space (i.e the maximum address that
can be presented to a 'Load' or 'Store' instruction); these larger
pointers can contain 64-bits of metadata (e.g. the size of the region
covered by the pointer and access controls for reads vs. writes)
allowing the processor to efficiently prevent access outside the bounds of an object,
or to prevent stores to a read-only object.

https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/cheri-faq.html

[toc] | [prev] | [next] | [standalone]


Page 1 of 3  [1] 2 3  Next page →

Back to top | Article view | comp.lang.c


csiph-web