Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #73016 > unrolled thread
| Started by | Alla _ <modelling.data@gmail.com> |
|---|---|
| First post | 2015-10-16 00:49 -0700 |
| Last post | 2015-10-17 13:59 -0700 |
| Articles | 20 on this page of 77 — 14 participants |
Back to article view | Back to comp.lang.c
Pointers, constant values Alla _ <modelling.data@gmail.com> - 2015-10-16 00:49 -0700
Re: Pointers, constant values Philip Lantz <prl@canterey.us> - 2015-10-16 01:49 -0700
Re: Pointers, constant values James Kuyper <jameskuyper@verizon.net> - 2015-10-16 09:41 -0400
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-16 08:55 -0700
Re: Pointers, constant values Keith Thompson <kst-u@mib.org> - 2015-10-16 08:25 -0700
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-16 09:11 -0700
Re: Pointers, constant values Keith Thompson <kst-u@mib.org> - 2015-10-16 12:06 -0700
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-16 12:55 -0700
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-16 17:49 +0100
Re: Pointers, constant values Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2015-10-16 13:23 -0400
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-16 19:34 +0100
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-16 12:05 -0700
Re: Pointers, constant values Keith Thompson <kst-u@mib.org> - 2015-10-16 12:18 -0700
Re: Pointers, constant values Keith Thompson <kst-u@mib.org> - 2015-10-16 12:13 -0700
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-16 20:33 +0100
Re: Pointers, constant values Keith Thompson <kst-u@mib.org> - 2015-10-16 13:01 -0700
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-16 21:09 +0100
Re: Pointers, constant values Keith Thompson <kst-u@mib.org> - 2015-10-16 13:41 -0700
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-16 21:07 +0100
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-16 21:20 +0100
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-16 22:02 +0100
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-16 22:21 +0100
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-16 14:39 -0700
Re: Pointers, constant values Keith Thompson <kst-u@mib.org> - 2015-10-16 15:26 -0700
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-16 15:44 -0700
Re: Pointers, constant values Keith Thompson <kst-u@mib.org> - 2015-10-16 16:58 -0700
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-16 17:28 -0700
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-16 22:50 +0100
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-16 15:14 -0700
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-17 01:23 +0100
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-17 19:39 +0100
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-17 22:42 +0100
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-18 00:31 +0100
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-18 02:11 +0100
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-18 11:59 +0100
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-18 12:12 +0100
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-18 12:28 +0100
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-18 23:16 +0100
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-18 23:34 +0100
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-19 01:45 +0100
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-19 11:51 +0100
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-19 12:55 +0100
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-19 13:51 +0100
Re: Pointers, constant values Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-10-19 06:02 -0700
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-19 07:02 -0700
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-19 15:39 +0100
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-19 08:54 -0700
Re: Pointers, constant values Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-10-19 09:14 -0700
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-19 10:21 -0700
Re: Pointers, constant values Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-10-19 12:57 -0700
Re: Pointers, constant values glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-10-19 21:20 +0000
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-20 20:50 -0700
Re: Pointers, constant values glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-10-21 04:58 +0000
Re: Pointers, constant values Keith Thompson <kst-u@mib.org> - 2015-10-19 08:40 -0700
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-19 20:17 +0100
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-17 16:44 -0700
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-18 11:52 +0100
Re: Pointers, constant values Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-10-18 05:15 -0700
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-18 21:54 +0100
Re: Pointers, constant values Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-10-18 16:09 -0700
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-18 07:55 -0700
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-18 21:47 +0100
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-18 15:37 -0700
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-19 00:10 +0100
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-18 19:04 -0700
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-16 21:13 +0100
Re: Pointers, constant values Ian Collins <ian-news@hotmail.com> - 2015-10-17 11:27 +1300
Re: Pointers, constant values Bartc <bc@freeuk.com> - 2015-10-17 00:56 +0100
Re: Pointers, constant values Les Cargill <lcargill99@comcast.com> - 2015-10-16 12:37 -0500
Re: Pointers, constant values James Kuyper <jameskuyper@verizon.net> - 2015-10-16 14:22 -0400
Re: Pointers, constant values Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-10-16 18:57 +0000
Re: Pointers, constant values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-16 20:40 +0100
Re: Pointers, constant values Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-10-16 20:46 +0000
Re: Pointers, constant values Keith Thompson <kst-u@mib.org> - 2015-10-16 14:24 -0700
Re: Pointers, constant values Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-10-19 12:43 +0000
Re: Pointers, constant values Siri Cruz <chine.bleu@yahoo.com> - 2015-10-16 13:20 -0700
Re: Pointers, constant values supercat@casperkitty.com - 2015-10-17 13:59 -0700
Page 2 of 4 — ← Prev page 1 [2] 3 4 Next page →
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-10-16 22:02 +0100 |
| Message-ID | <871tcur0gn.fsf@bsb.me.uk> |
| In reply to | #73068 |
Bartc <bc@freeuk.com> writes:
> On 16/10/2015 21:07, Ben Bacarisse wrote:
>> Bartc <bc@freeuk.com> writes:
>>
>>> On 16/10/2015 20:13, Keith Thompson wrote:
>>>> Bartc <bc@freeuk.com> writes:
>>>
>>>>> int array_sum(int (*array)[], int n);
>>>>
>>>> Yes, but there's not much you can do with it, since you haven't
>>>> specified the length of the array it points to. (I'm a little surprised
>>>> that that declaration is legal.)
>>>
>>> It's a pointer to an unbounded array.
>>
>> It's a pointer to an incomplete array type and, as such, is compatible
>> with a pointer to an int array of any length. Talking about an
>> unbounded array in C sounds very odd to me (but I did know what you
>> mean).
>
> It's the error you get if you compile with g++; it talks about unknown
> bounds.
To me, an incomplete array type is one whose size (i.e. bound is
unknown) so I have no problem with that error message. But an unbounded
array is one that has no size (or bound), and that's not a thing in C.
>> In C99 there's no reason not to go the whole hog and write
>>
>> int array_sum(int n, int (*data)[n]) { ... }
>
> Possibly, if you're passing the length too.
Yes, that's why n is repeated.
>> Now you *can* ask about sizeof *data, and even the usual ARRAY_SIZE
>> macro trick will work[1]. Of course the answer will be n, so there's
>> not much point, but then there was not much point in passing a pointer
>> to an array in the first place!
>
> Why not? If you want to access the array from inside the function, my
> point is it makes more sense, type-wise, to pass a pointer to the
> array, rather than a pointer to an int.
I don't want to argue about what "not much point" is. Maybe you see
enough point that it exceeds your threshold for "not much". That's
fine. If so, I offer the C99 option as slightly more useful.
<snip>
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-10-16 22:21 +0100 |
| Message-ID | <mvrpkd$qec$1@dont-email.me> |
| In reply to | #73079 |
On 16/10/2015 22:02, Ben Bacarisse wrote: > Bartc <bc@freeuk.com> writes: >> Why not? If you want to access the array from inside the function, my >> point is it makes more sense, type-wise, to pass a pointer to the >> array, rather than a pointer to an int. > > I don't want to argue about what "not much point" is. Maybe you see > enough point that it exceeds your threshold for "not much". That's > fine. If so, I offer the C99 option as slightly more useful. The 'point' is that in what seems to be 99% of C code, the wrong type is being passed. Arrays are turned into pointers to one element which are then turned back to arrays by means of applying offsets to them and treating them as arrays. C allows this, it's convenient, and everyone turns a blind eye. (Including me when I write C. But one translating a stricter language to C, it's not possible be to be that sloppy.) -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2015-10-16 14:39 -0700 |
| Message-ID | <b3460f50-037e-4c93-87f5-58587d8e8374@googlegroups.com> |
| In reply to | #73083 |
On Friday, October 16, 2015 at 4:21:23 PM UTC-5, Bart wrote: > Arrays are turned into pointers to one element which are then turned > back to arrays by means of applying offsets to them and treating them as > arrays. C allows this, it's convenient, and everyone turns a blind eye. They aren't turned back into arrays. In C as originally defined, a pointer may be viewed as identifying a "char[]" (since changed to 'unsigned char[]') and an offset into it (in many implementations, all of memory behaves as one giant char[], but that's hardly required). The C89 rules which prohibit writing data as one type and reading as another interact rather oddly with such a view, but there are many kinds of programming where, even abiding by the "dubious" rules of C89, no other view of the system would really make sense.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-10-16 15:26 -0700 |
| Message-ID | <ln37xa4fi8.fsf@kst-u.example.com> |
| In reply to | #73092 |
supercat@casperkitty.com writes:
> On Friday, October 16, 2015 at 4:21:23 PM UTC-5, Bart wrote:
>> Arrays are turned into pointers to one element which are then turned
>> back to arrays by means of applying offsets to them and treating them as
>> arrays. C allows this, it's convenient, and everyone turns a blind eye.
>
> They aren't turned back into arrays. In C as originally defined, a pointer
> may be viewed as identifying a "char[]" (since changed to 'unsigned char[]')
> and an offset into it (in many implementations, all of memory behaves as one
> giant char[], but that's hardly required).
You can view a pointer as anything you like, but C has always viewed a
pointer of type FOO* as identifying an object of type FOO.
> The C89 rules which prohibit
> writing data as one type and reading as another interact rather oddly with
> such a view, but there are many kinds of programming where, even abiding
> by the "dubious" rules of C89, no other view of the system would really
> make sense.
The rule you're referring to (which exists in C89/C90, in C99, and in
C11) does not completely prohibit writing data as one type and reading
as another. It explicitly permits accessing an object via an lvalue of
character type.
An object's representation is described in terms of an array of unsigned
char, but that's not particularly relevant to the current discussion
about pointers and arrays.
--
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 | supercat@casperkitty.com |
|---|---|
| Date | 2015-10-16 15:44 -0700 |
| Message-ID | <c7944465-bc6a-4740-9f19-e8dbf139c21c@googlegroups.com> |
| In reply to | #73100 |
On Friday, October 16, 2015 at 5:26:15 PM UTC-5, Keith Thompson wrote:
> You can view a pointer as anything you like, but C has always viewed a
> pointer of type FOO* as identifying an object of type FOO.
Given:
FOO foo;
FOO *thing = malloc(1+3*sizeof (FOO));
FOO *fp=thing;
for (int i=0; i<3; i++)
*fp++ = foo;
/*******/
unsigned char *cp = (unsigned char*) fp;
*cp = 23;
How would you describe the contents of "fp" at the line marked with the
asterisks? I'd describe things by saying that "malloc" created an array
of unsigned char, and that fp identifies a spot in that array. The
contents of fp are not meaningless, and are indeed vital to the correct
operation of the code, but it doesn't identify a "FOO" object nor even
a place where one could be placed (unless sizeof(FOO) equals 1).
> > The C89 rules which prohibit
> > writing data as one type and reading as another interact rather oddly with
> > such a view, but there are many kinds of programming where, even abiding
> > by the "dubious" rules of C89, no other view of the system would really
> > make sense.
>
> The rule you're referring to (which exists in C89/C90, in C99, and in
> C11) does not completely prohibit writing data as one type and reading
> as another. It explicitly permits accessing an object via an lvalue of
> character type.
I didn't want to get into a discussion of the details of the rule nor its
merits, but merely observe that there are many cases where code may use
pointers which only make sense if one views them fundamentally as pointing
into a character-type array [btw, I think C would have benefited from
having the "pointer to anything" type actually identify a "typeless memory
byte" rather than not identifying anything, so as to avoid the need to
always cast void* to unsigned char*.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-10-16 16:58 -0700 |
| Message-ID | <lnmvvi2wo1.fsf@kst-u.example.com> |
| In reply to | #73107 |
supercat@casperkitty.com writes:
> On Friday, October 16, 2015 at 5:26:15 PM UTC-5, Keith Thompson wrote:
>> You can view a pointer as anything you like, but C has always viewed a
>> pointer of type FOO* as identifying an object of type FOO.
>
> Given:
> FOO foo;
> FOO *thing = malloc(1+3*sizeof (FOO));
> FOO *fp=thing;
> for (int i=0; i<3; i++)
> *fp++ = foo;
> /*******/
> unsigned char *cp = (unsigned char*) fp;
> *cp = 23;
>
> How would you describe the contents of "fp" at the line marked with the
> asterisks? I'd describe things by saying that "malloc" created an array
> of unsigned char, and that fp identifies a spot in that array. The
> contents of fp are not meaningless, and are indeed vital to the correct
> operation of the code, but it doesn't identify a "FOO" object nor even
> a place where one could be placed (unless sizeof(FOO) equals 1).
Sure, and a FOO* doesn't identify an object of type FOO if it's a null
pointer, or if it points just past the end of an array. The expression
*fp is still of type FOO, whatever contrived examples you use to show
that there doesn't have to be an object for it to point to.
[...]
--
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 | supercat@casperkitty.com |
|---|---|
| Date | 2015-10-16 17:28 -0700 |
| Message-ID | <b4b83ed4-0358-41c6-9aca-2fe19532d10e@googlegroups.com> |
| In reply to | #73114 |
On Friday, October 16, 2015 at 6:58:27 PM UTC-5, Keith Thompson wrote: > Sure, and a FOO* doesn't identify an object of type FOO if it's a null > pointer, or if it points just past the end of an array. The expression > *fp is still of type FOO, whatever contrived examples you use to show > that there doesn't have to be an object for it to point to. What is the significance of *fp? I would suggest that it serves to identify a location within the "char[]" created by "malloc()" in which an object can be placed without overwriting anything previous to it. Casting between pointer types is well-defined behavior in C, and I would suggest that in a case like this it is fundamentally defined in terms of the underlying "char[]" created by malloc.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-10-16 22:50 +0100 |
| Message-ID | <87vba6pjow.fsf@bsb.me.uk> |
| In reply to | #73083 |
Bartc <bc@freeuk.com> writes: > On 16/10/2015 22:02, Ben Bacarisse wrote: >> Bartc <bc@freeuk.com> writes: > >>> Why not? If you want to access the array from inside the function, my >>> point is it makes more sense, type-wise, to pass a pointer to the >>> array, rather than a pointer to an int. >> >> I don't want to argue about what "not much point" is. Maybe you see >> enough point that it exceeds your threshold for "not much". That's >> fine. If so, I offer the C99 option as slightly more useful. > > The 'point' is that in what seems to be 99% of C code, the wrong type > is being passed. Surely that depends on what type you want to pass. When doing most array operations I don't "want" (in the language-agnostic sense) to pass a pointer to anything at all. I want to pass the array so that it can be accessed simply and efficiently. Both the usual C way (pass an pointer to the start) and the less usual way (pass a pointer to the whole array) are wrong in that sense of that word. But given C's restrictions, even passing a pointer to the array is the wrong type since you can't tell if this is a real pointer to an array or a pointer to an array or these arrays. In effect, you just move the problem up a level. > Arrays are turned into pointers to one element which are then turned > back to arrays No. There is an implicit array to pointer conversion, but no implicit pointer to array conversion. Suggesting that there is (by using your symmetrical phrasing) is just polemic. > by means of applying offsets to them and treating them as arrays. C > allows this, it's convenient, and everyone turns a blind eye. I don't turn a blind eye. I know exactly what's going on. And since passing a pointer to the array is usually as "wrong" (to borrow your phrase) as passing a pointer to the start of it, there is no reason not to use the convenient alternative. <snip> -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2015-10-16 15:14 -0700 |
| Message-ID | <0504d246-7d17-4e33-b530-c6ca220f85eb@googlegroups.com> |
| In reply to | #73093 |
On Friday, October 16, 2015 at 4:50:18 PM UTC-5, Ben Bacarisse wrote:
> Surely that depends on what type you want to pass. When doing most
> array operations I don't "want" (in the language-agnostic sense) to pass
> a pointer to anything at all. I want to pass the array so that it can
> be accessed simply and efficiently. Both the usual C way (pass an
> pointer to the start) and the less usual way (pass a pointer to the
> whole array) are wrong in that sense of that word.
C's type system has never been able to handle the concept of a non-constant
sized array in anything other than the context of automatic variables.
Some early C compilers supported the "size-zero struct hack", which was
legitimate on the compilers that supported it; since C89 forbade that, a
lot of C89 code used the size-one struct hack, which from the point of
view of the Standard clearly invokes Undefined Behavior, but which compiler
writers supported because they the generation of code that serves a useful
purpose as more important than the generation of the most efficient
possible code that meets the Standard.
C99 allowed flexible array members, which made the kinds of code that
used the size-1 hack legitimate, but didn't allow everything useful that
could be done with the size-zero hack, since given a type e.g.
struct SIZED_THING { uint32_t size; uint16_t data[]; };
there's no reasonable way to declare a variable of automatic or static
duration whose address is type-compatible with SIZED_THING*. If one
declares
struct SIZE_4_THING { uint32_t size; uint16_t data[4]; };
strict SIZE_4_THING const my_size_4_thing =
{4,{1,2,3,4};
the storage layout is guaranteed to be compatible with SIZED_THING, but
so far as I can tell no version of the C standard yet provides a
reasonable means of converting &my_size_4_thing into a SIZED_THING* that
can actually be used as a pointer to the latter type without invoking
Undefined Behavior [an implementation would be allowed to set the initial
contents of my_size_4_thing by writing it as a structure of that type,
and thus reading it as any other type, iuncluding SIZED_THING* would
invoke Undefined Behavior].
[toc] | [prev] | [next] | [standalone]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-10-17 01:23 +0100 |
| Message-ID | <mvs4b1$ve1$1@dont-email.me> |
| In reply to | #73093 |
On 16/10/2015 22:50, Ben Bacarisse wrote:
> Bartc <bc@freeuk.com> writes:
>
>> On 16/10/2015 22:02, Ben Bacarisse wrote:
>>> Bartc <bc@freeuk.com> writes:
>>
>>>> Why not? If you want to access the array from inside the function, my
>>>> point is it makes more sense, type-wise, to pass a pointer to the
>>>> array, rather than a pointer to an int.
>>>
>>> I don't want to argue about what "not much point" is. Maybe you see
>>> enough point that it exceeds your threshold for "not much". That's
>>> fine. If so, I offer the C99 option as slightly more useful.
>>
>> The 'point' is that in what seems to be 99% of C code, the wrong type
>> is being passed.
>
> Surely that depends on what type you want to pass.
Arrays, or the closest that C can manage. Whenever an array of T needs
to be passed to a function, then invariably, a T* pointer will be passed
instead.
So despite having an array object at one end, and accessing that array
object at the other, the bit in the middle - the parameter type - isn't
an array at all, not even a pointer to an array.
>> by means of applying offsets to them and treating them as arrays. C
>> allows this, it's convenient, and everyone turns a blind eye.
>
> I don't turn a blind eye. I know exactly what's going on. And since
> passing a pointer to the array is usually as "wrong" (to borrow your
> phrase) as passing a pointer to the start of it, there is no reason not
> to use the convenient alternative.
C can't pass value arrays. Then you can pass a pointer, which is usually
preferable anyway. The question is, what kind of pointer?
If the array is of type T, then the choice is between passing T(*)[] and
T*. So:
Caller: Parameter Dereferenced in callee:
(1) T[] T* T
(2) T[] T(*)[] T[]
(The dereference is an operation that C can't do directly for pointers
to arrays, as it can't deal with actual array values, and the bounds
might be missing anyway, but it can do so just before applying a []
indexing op.)
Here, using T* for the parameter (1), the original T[] can't be
recovered. With the T(*)[] parameter (2), it can. That's why (1) is wrong.
Also, with (1), it's possible to pass a pointer to a scalar, instead of
an array, another reason why it's wrong if the callee expects the latter.
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-10-17 19:39 +0100 |
| Message-ID | <87mvvhnxun.fsf@bsb.me.uk> |
| In reply to | #73118 |
Bartc <bc@freeuk.com> writes: > On 16/10/2015 22:50, Ben Bacarisse wrote: >> Bartc <bc@freeuk.com> writes: >> >>> On 16/10/2015 22:02, Ben Bacarisse wrote: >>>> Bartc <bc@freeuk.com> writes: >>> >>>>> Why not? If you want to access the array from inside the function, my >>>>> point is it makes more sense, type-wise, to pass a pointer to the >>>>> array, rather than a pointer to an int. >>>> >>>> I don't want to argue about what "not much point" is. Maybe you see >>>> enough point that it exceeds your threshold for "not much". That's >>>> fine. If so, I offer the C99 option as slightly more useful. >>> >>> The 'point' is that in what seems to be 99% of C code, the wrong type >>> is being passed. >> >> Surely that depends on what type you want to pass. > > Arrays, or the closest that C can manage. Whenever an array of T needs > to be passed to a function, then invariably, a T* pointer will be > passed instead. Well not quite invariably, no, but in the vast majority of cases, yes. Why is that, do you think? You hinted that programmers are being sloppy here or are are just turning a blind eye, but you know that some who are perfectly well aware of the alternatives, choose to pass a pointer to the start rather than to the whole array. <snip> > C can't pass value arrays. Then you can pass a pointer, which is > usually preferable anyway. The question is, what kind of pointer? > > If the array is of type T, then the choice is between passing T(*)[] > and T*. So: > > Caller: Parameter Dereferenced in callee: > > (1) T[] T* T > (2) T[] T(*)[] T[] > > (The dereference is an operation that C can't do directly for pointers > to arrays, as it can't deal with actual array values, and the bounds > might be missing anyway, but it can do so just before applying a [] > indexing op.) > > Here, using T* for the parameter (1), the original T[] can't be > recovered. With the T(*)[] parameter (2), it can. Only in some cases. Interestingly *not* the case you championed that started all this off. In that case the array type was incomplete, so you can't recover it in any useful way. But I agree that you can, in other cases, recover useful things about the array. (The only useful thing I can think of is the size, but maybe you have something else in mind.) > That's why (1) is wrong. Yes, I agree. But you are avoiding saying that (2) is wrong too. Instead, you've invented a notion of which wrong type is "closer" to the type we'd really like to pass if C allowed it. But much more important to the programmer is to decide which of the two pointer types is more convenient most of the time, and I don't think that's really debatable, do you? <snip> -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-10-17 22:42 +0100 |
| Message-ID | <mvuf8g$c1i$1@dont-email.me> |
| In reply to | #73153 |
On 17/10/2015 19:39, Ben Bacarisse wrote: > Bartc <bc@freeuk.com> writes: >> Arrays, or the closest that C can manage. Whenever an array of T needs >> to be passed to a function, then invariably, a T* pointer will be >> passed instead. > > Well not quite invariably, no, but in the vast majority of cases, yes. > Why is that, do you think? Because to do it my way (ie. 'properly') requires an explicit dereference of the array (to index it in the callee). And because '*' is a prefix op, it also needs extra parentheses. So it is a PITA (to answer one of your other comments). When I have to write C manually, I don't bother either... > You hinted that programmers are being sloppy ... but it doesn't change the fact that passing a T* type is a rather sloppy way of doing it. (Because there is no protection against passing a pointer to a scalar, amongst other reasons.) I came into the thread when Keith said there was no real array parameter type in C, and gave alternatives of T* and T[] (which are identical). I simply gave a little-used alternative which is closer to what is really wanted. >> If the array is of type T, then the choice is between passing T(*)[] >> and T*. So: >> >> Caller: Parameter Dereferenced in callee: >> (1) T[] T* T >> (2) T[] T(*)[] T[] >> Here, using T* for the parameter (1), the original T[] can't be >> recovered. With the T(*)[] parameter (2), it can. > > Only in some cases. Interestingly *not* the case you championed that > started all this off. In that case the array type was incomplete, so > you can't recover it in any useful way. That's not true; I could specify fixed bounds if I wanted to. If I wanted to keep it general for arrays of any size, then I think I could use your method of passing 'int n' and then using n for the bounds, although 'int n' apparently has to be specified first. >> That's why (1) is wrong. > > Yes, I agree. But you are avoiding saying that (2) is wrong too. > Instead, you've invented a notion of which wrong type is "closer" to the > type we'd really like to pass if C allowed it. This is how I discovered this way of passing arrays: I needed to translate a language which didn't conflate arrays and pointers as C does, into structured C source code. The process naturally converts a pointer-to-array of T into T(*)[]. The array (the pointer target) can be bounded or unbounded. It would actually be more difficult to convert into T*. Since this is an automatic process, it suggests that T(*)[] is the /the/ correct way of passing a pointer-to-T[]. -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-10-18 00:31 +0100 |
| Message-ID | <87bnbxnkba.fsf@bsb.me.uk> |
| In reply to | #73157 |
Bartc <bc@freeuk.com> writes:
> On 17/10/2015 19:39, Ben Bacarisse wrote:
>> Bartc <bc@freeuk.com> writes:
>
>>> Arrays, or the closest that C can manage. Whenever an array of T needs
>>> to be passed to a function, then invariably, a T* pointer will be
>>> passed instead.
>>
>> Well not quite invariably, no, but in the vast majority of cases, yes.
>> Why is that, do you think?
>
> Because to do it my way (ie. 'properly') requires an explicit
> dereference of the array (to index it in the callee). And because '*'
> is a prefix op, it also needs extra parentheses. So it is a PITA (to
> answer one of your other comments).
>
> When I have to write C manually, I don't bother either...
I'm sorry to be blunt, but I don't think you are arguing in good faith.
I don't think that when you write perfectly normal, safe, idiomatic C,
using the usual method of passing a pointer to the start of some data,
you are "not bothering" to do it right. I think you know you are doing
it the best way, but you just don't like it because you don't like C
(something that you are have made no bones about).
But let me atke you ate your word and see what writing C properly C
looks like. Here, for example, is what I'd write (because, according to
you I don't bother to do it property either) when I want a divide an
conquer algorithm. (I wanted to use quick sort but it's complexity
obscures the issue, so please ignore the fact that one would not use
divide and conquer for this problem.)
int max(int a, int b) { return a > b ? a : b; }
int amax(int n, const int *data)
{
if (n > 1)
return max(amax(n/2, data), amax(n - n/2, &data[n/2]));
else if (n == 1)
return data[0];
else abort();
}
...
int n, d[MAX_SIZE];
...
printf("max = %d\n", amax(n, d));
If you *could* be bothered, how would you write this properly?
<snip>
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-10-18 02:11 +0100 |
| Message-ID | <mvurfu$k3o$1@dont-email.me> |
| In reply to | #73171 |
On 18/10/2015 00:31, Ben Bacarisse wrote:
> Bartc <bc@freeuk.com> writes:
>> When I have to write C manually, I don't bother either...
>
> I'm sorry to be blunt, but I don't think you are arguing in good faith.
> I don't think that when you write perfectly normal, safe, idiomatic C,
> using the usual method of passing a pointer to the start of some data,
> you are "not bothering" to do it right.
You're using pointers and buffers rather than arrays; to me they are
different, if not to C. That wouldn't so bad if you just used *(p+i) to
access them, but C allows p[i] which mixes things up.
> I think you know you are doing
> it the best way, but you just don't like it because you don't like C
> (something that you are have made no bones about).
Not at all. I think C is my favourite language (other than one of my own).
> But let me atke you ate your word and see what writing C properly C
> looks like. Here, for example, is what I'd write (because, according to
> you I don't bother to do it property either) when I want a divide an
> conquer algorithm. (I wanted to use quick sort but it's complexity
> obscures the issue, so please ignore the fact that one would not use
> divide and conquer for this problem.)
> int amax(int n, const int *data)
> {
> if (n > 1)
> return max(amax(n/2, data), amax(n - n/2, &data[n/2]));
> else if (n == 1)
> return data[0];
> else abort();
> }
> If you *could* be bothered, how would you write this properly?
This really involves array slices, which C doesn't have so a solution in
C would be untidy. (My compiled language doesn't have slice denotations
either, but it's less of a problem than in C.)
So if writing in actual C and wanting to keep to arrays or pointers to
arrays, I would probably add two or three slicing functions (input is a
pointer to array and one or two numbers, output is a pointer to another
part of the array. Casts would need to be involved).
For this example I might create left() and right() functions, then
recoding your example would be straightforward. But not as simple.
(How would modern Fortran, or Ada, handle this example? I suspect they
don't use just pointers like C does!)
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-10-18 11:59 +0100 |
| Message-ID | <87zizgmohd.fsf@bsb.me.uk> |
| In reply to | #73181 |
Bartc <bc@freeuk.com> writes:
> On 18/10/2015 00:31, Ben Bacarisse wrote:
>> Bartc <bc@freeuk.com> writes:
>
>>> When I have to write C manually, I don't bother either...
>>
>> I'm sorry to be blunt, but I don't think you are arguing in good faith.
>> I don't think that when you write perfectly normal, safe, idiomatic C,
>> using the usual method of passing a pointer to the start of some data,
>> you are "not bothering" to do it right.
>
> You're using pointers and buffers rather than arrays; to me they are
> different, if not to C. That wouldn't so bad if you just used *(p+i)
> to access them, but C allows p[i] which mixes things up.
>
>> I think you know you are doing
>> it the best way, but you just don't like it because you don't like C
>> (something that you are have made no bones about).
>
> Not at all. I think C is my favourite language (other than one of my own).
>
>> But let me atke you ate your word and see what writing C properly C
>> looks like. Here, for example, is what I'd write (because, according to
>> you I don't bother to do it property either) when I want a divide an
>> conquer algorithm. (I wanted to use quick sort but it's complexity
>> obscures the issue, so please ignore the fact that one would not use
>> divide and conquer for this problem.)
>
>> int amax(int n, const int *data)
>> {
>> if (n > 1)
>> return max(amax(n/2, data), amax(n - n/2, &data[n/2]));
>> else if (n == 1)
>> return data[0];
>> else abort();
>> }
>
>> If you *could* be bothered, how would you write this properly?
>
> This really involves array slices, which C doesn't have so a solution
> in C would be untidy. (My compiled language doesn't have slice
> denotations either, but it's less of a problem than in C.)
>
> So if writing in actual C and wanting to keep to arrays or pointers to
> arrays, I would probably add two or three slicing functions (input is
> a pointer to array and one or two numbers, output is a pointer to
> another part of the array. Casts would need to be involved).
>
> For this example I might create left() and right() functions, then
> recoding your example would be straightforward. But not as simple.
In case it's not obvious, my point was to try to shake your claim that
you (and your suggestion that I) don't write C array code "properly"
just because we "can't be bothered". It's a very great deal of bother
isn't it? Especially compared to to how simple, safe and elegant the
"wrong" way is.
<snip>
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-10-18 12:12 +0100 |
| Message-ID | <mvvum2$f1b$1@dont-email.me> |
| In reply to | #73197 |
On 18/10/2015 11:59, Ben Bacarisse wrote:
> Bartc <bc@freeuk.com> writes:
>> On 18/10/2015 00:31, Ben Bacarisse wrote:
>>> int amax(int n, const int *data)
>>> {
>>> if (n > 1)
>>> return max(amax(n/2, data), amax(n - n/2, &data[n/2]));
>>> else if (n == 1)
>>> return data[0];
>>> else abort();
>>> }
>>
>>> If you *could* be bothered, how would you write this properly?
>>
>> This really involves array slices, which C doesn't have so a solution
>> in C would be untidy. (My compiled language doesn't have slice
>> denotations either, but it's less of a problem than in C.)
>> For this example I might create left() and right() functions, then
>> recoding your example would be straightforward. But not as simple.
>
> In case it's not obvious, my point was to try to shake your claim that
> you (and your suggestion that I) don't write C array code "properly"
> just because we "can't be bothered". It's a very great deal of bother
> isn't it? Especially compared to to how simple, safe and elegant the
> "wrong" way is.
It might be simple and elegant, but you're breaking out of the type
system IMV. Admittedly C is aiding and abetting, so I guess that makes
it alright.
My C version is below. It doesn't use bare pointers to integers, only to
arrays (apart from the machinations C might need for its internal workings):
#include <stdio.h>
#include <stdlib.h>
//Take an unbounded pointer-array A, and return another unbounded
//pointer-to-array starting at element [n]
#define slicefrom(A,n) ((int(*)[])&((*A)[n]))
int max(int a, int b) { return a > b ? a : b; }
int amax(int (*data)[], int n) {
if (n > 1)
return max(amax(slicefrom(data,0),n/2),
amax(slicefrom(data,n/2), n-n/2));
else if (n == 1)
return (*data)[0];
else
exit(0);
}
int main(void) {
int d[]={1,4,2,8,5,7};
printf("max = %d\n", amax(&d, 6));
}
(The slicing done here doesn't take account of lengths. That would need
a much more thorough treatment. slicefrom(A,0) just returns A, but it
uses it to emphasise that a slice of the original array is being worked
with.)
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-10-18 12:28 +0100 |
| Message-ID | <mvvvku$ib9$1@dont-email.me> |
| In reply to | #73198 |
On 18/10/2015 12:12, Bartc wrote: > On 18/10/2015 11:59, Ben Bacarisse wrote: >> In case it's not obvious, my point was to try to shake your claim that >> you (and your suggestion that I) don't write C array code "properly" >> just because we "can't be bothered". It's a very great deal of bother >> isn't it? Especially compared to to how simple, safe and elegant the >> "wrong" way is. > My C version is below. It doesn't use bare pointers to integers, only to > arrays (apart from the machinations C might need for its internal > workings): (As a further perspective, here is the same code in my own language: http://pastebin.com/ihk0Ltbc Both pointer-based and array-based versions are given. This language provides automatic conversions between T* and S* types, which is is rather slack, but strongly enforces the difference between pointer and array operations.) -- Bartc
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-10-18 23:16 +0100 |
| Message-ID | <87wpujlt5f.fsf@bsb.me.uk> |
| In reply to | #73198 |
Bartc <bc@freeuk.com> writes:
> On 18/10/2015 11:59, Ben Bacarisse wrote:
>> Bartc <bc@freeuk.com> writes:
>>> On 18/10/2015 00:31, Ben Bacarisse wrote:
>
>>>> int amax(int n, const int *data)
>>>> {
>>>> if (n > 1)
>>>> return max(amax(n/2, data), amax(n - n/2, &data[n/2]));
>>>> else if (n == 1)
>>>> return data[0];
>>>> else abort();
>>>> }
>>>
>>>> If you *could* be bothered, how would you write this properly?
>>>
>>> This really involves array slices, which C doesn't have so a solution
>>> in C would be untidy. (My compiled language doesn't have slice
>>> denotations either, but it's less of a problem than in C.)
>
>>> For this example I might create left() and right() functions, then
>>> recoding your example would be straightforward. But not as simple.
>>
>> In case it's not obvious, my point was to try to shake your claim that
>> you (and your suggestion that I) don't write C array code "properly"
>> just because we "can't be bothered". It's a very great deal of bother
>> isn't it? Especially compared to to how simple, safe and elegant the
>> "wrong" way is.
>
> It might be simple and elegant, but you're breaking out of the type
> system IMV. Admittedly C is aiding and abetting, so I guess that makes
> it alright.
All the types match up correctly with no casts needed. They are,
according to you the wrong types, but that's another matter.
> My C version is below. It doesn't use bare pointers to integers, only
> to arrays (apart from the machinations C might need for its internal
> workings):
>
> #include <stdio.h>
> #include <stdlib.h>
>
> //Take an unbounded pointer-array A, and return another unbounded
> //pointer-to-array starting at element [n]
> #define slicefrom(A,n) ((int(*)[])&((*A)[n]))
This is "breaking out of the type system" in spades. Just force the
type to be whatever you need it to be with a cast.
> int max(int a, int b) { return a > b ? a : b; }
>
> int amax(int (*data)[], int n) {
Why did you try drop the const? Did you not want to show that even the
top-level call would then need a cast to force the types to match?
This discussion has entered a sort of twilight world where the "right"
type to use needs casts to force the code to compile, whilst C is
accused of criminal behaviour ("aiding and abetting") because it
provides a simple, safe alternative type that is "wrong".
<snip>
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-10-18 23:34 +0100 |
| Message-ID | <n016ml$akq$1@dont-email.me> |
| In reply to | #73245 |
On 18/10/2015 23:16, Ben Bacarisse wrote:
> Bartc <bc@freeuk.com> writes:
>> It might be simple and elegant, but you're breaking out of the type
>> system IMV. Admittedly C is aiding and abetting, so I guess that makes
>> it alright.
>
> All the types match up correctly with no casts needed. They are,
> according to you the wrong types, but that's another matter.
No casts are needed partly because C will change a T[] to T* without
intervention. You go from working with arrays and indices in the caller,
to pointers and offsets in the callee.
>> My C version is below. It doesn't use bare pointers to integers, only
>> to arrays (apart from the machinations C might need for its internal
>> workings):
>>
>> #include <stdio.h>
>> #include <stdlib.h>
>>
>> //Take an unbounded pointer-array A, and return another unbounded
>> //pointer-to-array starting at element [n]
>> #define slicefrom(A,n) ((int(*)[])&((*A)[n]))
>
> This is "breaking out of the type system" in spades.
True... but unavoidable to work with T(*)[] types. But it is at least
out of the way. The important thing is that you pass T(*)[] to a
function and still have a T(*)[] at the other end.
(No-one has yet mentioned how this works in other languages. Pointers
and arrays being interchangeable must surely be only another C thing.)
>> int amax(int (*data)[], int n) {
>
> Why did you try drop the const? Did you not want to show that even the
> top-level call would then need a cast to force the types to match?
I never use const (why not would be another thread). My code was a
self-contained program and it worked fine without it.
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-10-19 01:45 +0100 |
| Message-ID | <87k2qjlm80.fsf@bsb.me.uk> |
| In reply to | #73249 |
Bartc <bc@freeuk.com> writes:
> On 18/10/2015 23:16, Ben Bacarisse wrote:
>> Bartc <bc@freeuk.com> writes:
>
>>> It might be simple and elegant, but you're breaking out of the type
>>> system IMV. Admittedly C is aiding and abetting, so I guess that makes
>>> it alright.
>>
>> All the types match up correctly with no casts needed. They are,
>> according to you the wrong types, but that's another matter.
>
> No casts are needed partly because C will change a T[] to T* without
> intervention. You go from working with arrays and indices in the
> caller, to pointers and offsets in the callee.
>
>>> My C version is below. It doesn't use bare pointers to integers, only
>>> to arrays (apart from the machinations C might need for its internal
>>> workings):
>>>
>>> #include <stdio.h>
>>> #include <stdlib.h>
>>>
>>> //Take an unbounded pointer-array A, and return another unbounded
>>> //pointer-to-array starting at element [n]
>>> #define slicefrom(A,n) ((int(*)[])&((*A)[n]))
>>
>> This is "breaking out of the type system" in spades.
>
> True... but unavoidable to work with T(*)[] types. But it is at least
> out of the way. The important thing is that you pass T(*)[] to a
> function and still have a T(*)[] at the other end.
Yes, that's the thing that matters! Hang the cast. Hang the casts on
top-level calls if you want to make the function const-safe. No matter
how the type system must be bent and battered, your "proper" type is the
right one!
> (No-one has yet mentioned how this works in other languages. Pointers
> and arrays being interchangeable must surely be only another C thing.)
It's very neat in Go:
func amax(data []int) int {
if l := len(data); l > 1 {
return max(amax(data[:l/2]), amax(data[l/2:]));
}
return data[0]
}
Go has a slice type which represents and sized and offset index into an
existing array. It's what C's arrays probably should have been.
(Every time I write Go I am sad that it was not designed sooner. We
might all be writing clearer code if it had been.)
And in Ada (though I'm less sure if this is really idiomatic):
function Amax(A: IntArray) return Integer is
L: Natural := A'Last - A'First + 1;
begin
if L > 1 then
return Integer'Max(Amax(A(A'First .. A'First + L/2 - 1)),
Amax(A(A'First + L/2 .. A'Last)));
else
return A(A'First);
end if;
end amax;
I's do Algol-68 for you know Algol-68 I think.
>>> int amax(int (*data)[], int n) {
>>
>> Why did you try drop the const? Did you not want to show that even the
>> top-level call would then need a cast to force the types to match?
>
> I never use const (why not would be another thread). My code was a
> self-contained program and it worked fine without it.
But any claim to know what the proper type to use must apply to C as a
whole. If all you meant is that "it works for me and the kind of C I
write" then I doubt I'd have taken the bait! Pointers to array types
have const issues, and these should be part of a discussion of which
wrong type us best to use for passing arrays around.
--
Ben.
[toc] | [prev] | [next] | [standalone]
Page 2 of 4 — ← Prev page 1 [2] 3 4 Next page →
Back to top | Article view | comp.lang.c
csiph-web