gcc: pointer to array

N

Netocrat

S.Tobias said:
Netocrat said:
Not true.
[snip]

Okay. :-| Then there must be something else wrong with you:

I wonder what it could be? I understand your arguments, and I don't
require you to agree with mine, but if you give them more
consideration, you will possibly find that they're at least reasonable.
Why do you keep writing things like this?

Because the void type is unique. It is the only type that is both
empty, incomplete and can never be completed. In that sense how can we
consider a void pointer as pointing to "an object"? - it is clear that
void is the only type that can never represent an object, so a void
pointer can never point to an object. It may, however, be validly
converted to a pointer type that does.
Void pointer *can*
point to *any* object, that's its main purpose.

Informally I would also use a statement like that. But I don't think
it's strictly true (and the standard's wording convinces me that it's
not).

We rely on 6.3.2.3#1 to be able to convert without information loss
from a non-void pointer to a void pointer and back again, but they are
different pointer types, and nothing in the standard says that when the
information is stored in a void pointer, that we must consider the
conceptual thing that is the "void pointer" to be "pointing to an
object"; the definition of the void type actually makes that wrong in
the strict sense (I agree that informally we might use such wording).
It's that
the object's value cannot be accessed through void type,

No value at all (==void,empty) can be accessed through the void type,
let alone an object.
the pointer has to be converted to other type (a different
pointer), but the whole expression is still based on the original
void pointer that points to that object, eg:
*(int*)vp;

If a void pointer doesn't point to an object, then where does
it point to?

How would you instead answer "what does it point to?"

I don't see a strictly correct answer to your question (informally I
would say that it points to the original object as you have been
claiming). I'd describe a void pointer rather as holding pointing
information in a form that can be transferred back to an object pointer
without loss of meaning. But I wouldn't describe it as an object
pointer itself.

Now regarding whether dereferencing a void pointer is defined
behaviour, I said:
I find the standard a little ambiguous here.
The first two sentences of 6.5.3.2#4 don't apply since by 6.2.5, void
is not an object, it's an incomplete type.

Can you see where that statement is coming from now? 6.5.3.2#4 says
that "if [the operand] points to an object, the result is an lvalue
designating the object", but since a void pointer by definition does
not point to an object, this statement doesn't apply to a void pointer.
That leaves things somewhat
undefined; the third sentence defines the resulting type, but is that
enough definition?

So all that's defined is that the result has void type. OK, given that
there is no such thing as a void object anyway, I'll answer my
question: yes, that's enough definition. So I'm satisfied that at
least this part of the standard defines and allows for the
dereferencing of a void pointer.

Now said:
[*] Well, actually 6.5.3.2#4 says it is an lvalue, but I think
the Standard is again wrong; I think it deserves a DR, but first
I'll check that this isn't already known.

You have misinterpreted 6.5.3.2#4. The result is only an lvalue if the
operand points to an object, which strictly speaking a void pointer
doesn't.

The paragraph says: "if it points to an object, the result is an lvalue
designating the object". Your argument implies that the object type
that the lvalue locates can be different to the type of expression
representing it (in this case, void), which is plainly untrue.

Don't get me wrong - I know that it's sometimes legal to access objects
through an lvalue of type other than the object's originally designated
type (in particular I'm a thinking of a character type), but in those
cases conceptually the lvalue _is_ accessing an object of the same type
as itself (eg. a char can be considered as a special object within a
bigger object of different type), whereas in the case of void it is not
(void is not an object like char is; it is empty and incompletable, so
an lvalue represented by a void expression cannot validly locate any
"object" within a different object).
 
P

pete

Netocrat said:
S.Tobias wrote:

How would you instead answer "what does it point to?"

Allocated memory.

N869
7.20.3.3 The malloc function
Synopsis
[#1]
#include <stdlib.h>
void *malloc(size_t size);
Description
[#2] The malloc function allocates space for an object whose
size is specified by size and whose value is indeterminate.
Returns
[#3] The malloc function returns either a null pointer or a
pointer to the allocated space.
 
N

Netocrat

pete said:
Allocated memory.

Spot on and concise as usual.

The distinction between allocated memory and an object is that an
object has a type - its definition requires it to be capable of
representing values.

So Stan perhaps you would be willing to consider that a void pointer is
best defined as pointing to allocated memory and not an object.
 
P

pete

Netocrat said:
Spot on and concise as usual.

The distinction between allocated memory and an object is that an
object has a type - its definition requires it to be capable of
representing values.

Maybe not.

N869
7.20.3 Memory management functions

Each such allocation shall yield a pointer to
an object disjoint from any other object.
 
C

Chris Torek

[I have been meaning to reply to this for quite a while now.]
[Given "int arr[N];" and considering "&arr" vs "&arr[0]")

I think the real question boils down to whether &arr and &arr[0]
will compare equal under *all* "well-defined" conversions -- which
may even be only those to "char *" and "void *" -- and then I think
the answer is "yes", so that we can in fact say that the converted
values are always identical as long as we do a sensible conversion.

Is that actually defined by the standard?

At least implicitly, yes (I think). I have tried to argue the
opposite and always seem to run into a contradiction somewhere.
This is not entirely a satisfactory proof. :)
I remember that in some pre-standard C compilers arrays were
actually implemented as pointers, so int arr[5]; would actually
expand to the equivalent in pseudo-assember:

arr: dw &_arr
_arr: dw ?[5]

(The array pointer itself might be declared in a read-only segment.)

This was true in BCPL and B, and even in NB, but not in C. See
<http://cm.bell-labs.com/cm/cs/who/dmr/chist.html> (the section
titled "Embryonic C"). Indeed, the elimination of the pointer
seems to have been the point at which the language's name changed
from "New B" to "C".
Is this sort of expansion actually banned by the standard ...

Yes. See Dennis' example with a struct that contains an array.
Where will you put the pointer?
 
N

Netocrat

Maybe not.

N869
7.20.3 Memory management functions

Each such allocation shall yield a pointer to an object disjoint
from any other object.

I hadn't looked at library functions. So what I described as "informal
wording" is actually used in the standard.

Stan said in a higher up post, "Object is an untyped range of bytes in the
run-time, nothing more. Type of an object is the type of the lvalue that
it is accessed with."

My idea of an object includes type (probably influenced by OO), but it
seems that Stan is correct and that C99 only requires that it "may" be
considered typed.

I don't think it's quite that clear-cut in C in general (the C89 draft
definition of an object, for example, doesn't use the word "type" at all
so there is no "may" qualification, but it specifically mentions
bit-fields, suggesting that type is an implicit property of an object).

So I will accept Stan's argument that by 6.5.3.2#4 dereferencing a void
pointer yields an lvalue which contradicts 6.3.2.1#1.

This problem would be solved if an object were necessarily typed and we
defined a void pointer as pointing to untyped storage, not an object, but
that's off-topic.
 
J

Joe Wright

Netocrat said:
I hadn't looked at library functions. So what I described as "informal
wording" is actually used in the standard.

Stan said in a higher up post, "Object is an untyped range of bytes in the
run-time, nothing more. Type of an object is the type of the lvalue that
it is accessed with."

My idea of an object includes type (probably influenced by OO), but it
seems that Stan is correct and that C99 only requires that it "may" be
considered typed.

I don't think it's quite that clear-cut in C in general (the C89 draft
definition of an object, for example, doesn't use the word "type" at all
so there is no "may" qualification, but it specifically mentions
bit-fields, suggesting that type is an implicit property of an object).

So I will accept Stan's argument that by 6.5.3.2#4 dereferencing a void
pointer yields an lvalue which contradicts 6.3.2.1#1.

This problem would be solved if an object were necessarily typed and we
defined a void pointer as pointing to untyped storage, not an object, but
that's off-topic.
You seem to insist of making simple things complicated. An object is
simply a region of one or more bytes of storage. It doesn't require a
type to be an object. Consider..

typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned short ushort;

typedef struct {
uchar version; /* 00 0x03 or 0x83 (with .dbt file) */
uchar date[3]; /* 01 Date YY MM DD in binary */
ulong numrecs; /* 04 Number of records in data file */
ushort hdrlen; /* 08 Offset to first record */
ushort reclen; /* 0A Length of each record */
uchar reserved[20];/* 0C Balance of 32 bytes */
} HEADER;

HEADER *head;
void *vp;
vp = malloc(sizeof *head);

Assuming success, malloc returns an address of type (void*) which points
to 32 bytes of storage. This address is assigned to vp. Now vp points to
an object of unspecified type of 32 bytes. No part of the object can be
accessed through vp.

head = vp;

Now head points to the same object as vp. But head has a complete type
(namely HEADER*) and so the object can be accessed as *head and any of
its members as (*head).hdrlen or head->hdrlen.
 
K

Keith Thompson

Netocrat said:
I can't argue against that. The draft document I use is plain-text
without italics.


I have accessed a later draft dated May 6 2005 with the same wording.
Can anyone comment on whether any committee members view the definition
as flawed?

When I raised this issue on comp.std.c some time ago, Doug Gwyn, who
is a committee member, seemed to think that my concerns were
incorrect. He did say at one point that the standard's definition of
lvalue needed more work, but not for the reasons I had been arguing;
he never explained what he meant.

The fundamental point of disagreement, I think, was about what a
"definition" should be. My position is that the definition of a
"foo", for example, should be sufficient to determine what is a foo
and what is not a foo. The definition can depend on terms defined
elsewhere, but once those terms are understood the definition itself
should be complete and unambiguous. Otherwise, though it may be a
useful statement about foos, it isn't a definition, and should not be
presented as one. This is especially important for invented terms
that are not expected to be understood

The C99 standard's so-called "definition" of the term "lvalue" is a
useful statement about lvalues, but since it does not allow the reader
to determine whether a given expression is an lvalue or not, I don't
consider it to be a valid definition.
 
N

Netocrat

Netocrat wrote:

[conceding that the standard defines an object as storage not necessarily
typed, and that wording that I initially called informal is actually used
by the standard (ie that a void pointer points to an object)]
You seem to insist of making simple things complicated.

Right, the current understanding that a void pointer points to potentially
untyped storage is better and more correct than considering its
destination as necessarily untyped.

But I do think that an object is best defined as typed.

Referring to object as not-necessarily-typed storage, the standard says:

6.5#6
If a value is stored into an object having no declared type through an
lvalue having a type that is not a character type, then the type of
the lvalue becomes the effective type of the object for that access
and for subsequent accesses that do not modify the stored value.

So using the standard:
untyped storage: a storage area returned by a memory allocation routine
and not yet assigned to.

In all other cases type has either been declared or determined by being
assigned to.

Untyped storage is the exception rather than the rule, and to me the term
object always connotes a type. So to me it is simpler to remove the
exceptional and unintuitive circumstance from the definition of object and
deal with it separately.

We could define:
an object: a typed data storage area
allocated storage: any defined or allocated data storage area including
untyped storage (as defined above)

Allocated storage would correspond to the current object definition.

All pointers must then point to allocated storage, which may or may not be
an object, and even if it is an object may not be the correct type. This
definition change would be reflected in the wording of 6.5.3.2#4, although
it wouldn't correct the current problem that dereferencing a void pointer
results in an lvalue.

I'm starting to get off-topic for clc though.
An object is
simply a region of one or more bytes of storage. It doesn't require a
type to be an object. Consider..

<snip>

Given that I'd already conceded that C99 defines an object that way, your
example didn't really add anything.
 
P

pete

Keith said:
The fundamental point of disagreement, I think, was about what a
"definition" should be.

Do you have IS0 1087 ?




ISOllEC 2382-l : 1993

Other terms such as vocabulary, concept, term and definition,
are used in this part of ISO/IEC 2382
with the meaning defined in IS0 1087.
 
K

Keith Thompson

pete said:
Do you have IS0 1087 ?




ISOllEC 2382-l : 1993

Other terms such as vocabulary, concept, term and definition,
are used in this part of ISO/IEC 2382
with the meaning defined in IS0 1087.

No, do you? Can someone summarize its definition of "definition"?
 
R

Robert Gamble

Keith said:
No, do you? Can someone summarize its definition of "definition"?

Definition:

ISO 1087:1990:
Statement which describes a concept and permits its differentiation
from other concepts within a system of concepts.

ISO 1087-1:2000:
Representation of a concept by a descriptive statement which serves to
differentiate it from related concepts.

Robert Gamble
 
P

pete

Keith Thompson wrote:
When I raised this issue on comp.std.c some time ago, Doug Gwyn, who
is a committee member, seemed to think that my concerns were
incorrect. He did say at one point that the standard's definition of
lvalue needed more work, but not for the reasons I had been arguing;
he never explained what he meant.

The fundamental point of disagreement, I think, was about what a
"definition" should be. My position is that the definition of a
"foo", for example, should be sufficient to determine what is a foo
and what is not a foo.

I remember that.

http://groups-beta.google.com/group/comp.std.c/msg/d40b6ab86fc45c00?hl=en&
 
K

Keith Thompson

Robert Gamble said:
Definition:

ISO 1087:1990:
Statement which describes a concept and permits its differentiation
from other concepts within a system of concepts.

ISO 1087-1:2000:
Representation of a concept by a descriptive statement which serves to
differentiate it from related concepts.

So as far as ISO 1087 is concerned, a "definition" distinguishes the
defined term from other terms, but doesn't necessarily distinguish
things that meet the definition from things that don't.

Sigh.
 
D

Dave Thompson

On 16 Jul 2005 17:18:54 GMT, "S.Tobias"
I don't think so. In C90 6.2.2.1 there's a paragraph which is equivalent
of 6.3.2.1#2 in C99 (in n869.txt) (they seem the same, but I haven't
checked). It means that at least the value of `*n' is not taken (because
it is operand to "&"). I don't see any cv in C90 except that `*n' is
not strictly an lvalue, which cannot (in general) be established at
compile time (due to poor definition of an lvalue).
They aren't the same; the difference is small but vital.

C90 says "An _lvalue_ is an expression (with an object type or
an incomplete type other than *void*) that designates an object."
plus the same footnote that is #46 in C99. The use of italics
means this is the definition of the term. Obviously for some
expressions like *ptr in some cases whether it designates an object
(and thus is an lvalue) can only be determined at runtime, making it
impossible to enforce constraints at compiletime as clearly intended.

C99 attempted to fix this by making the "designate an object" a
_separate_ requirement not part of the definition. Unfortunately, as
you and Netocrat have discussed at great length, IINM significantly
greater length than the scores if not hundreds of times this has been
discussed previously, the changed wording taken literally allows
essentially all expressions including pure (r)values that can
(trivially) and should be rejected at compiletime.

Since various types and forms of expressions are specified as yielding
an lvalue or a non-lvalue based only on compiletime information, the
intent is clear to any reader familiar with general computer and 3GL
principles or the history of C or both; there is no evidence that
anyone has actually misunderstood this intent not just for debating
purposes; and the Standard committee apparently has had enough work on
real issues to keep it too busy to fix this.

- David.Thompson1 at worldnet.att.net
 
D

Dave Thompson

Yup, that all works fine Dave but what Alexei actually wanted was more
specific and can't be done - at least no one who's responded to this
thread so far has found a way.

He wanted to pass a pointer to an array of a certain number of elements
(i.e. your first prototype is insufficient, but your second is sufficient)
into a function and be guaranteed that the contents of the array could not
be modified within the function. But he also wanted to be able to pass in
parameters of a type that were not const-qualified in any way eg.
int(*)[5], and have them automatically cast to the required type ie const
int (*)[5]. But this seems to be prohibited by C's automatic
const-conversion rules.

Sorry, I forgot that part and answered only what he and you said in
these particular posts. Yes, there is no way to silently add const
within an array. Unfortunately.
- David.Thompson1 at worldnet.att.net
 
N

Netocrat

Dave said:
On 16 Jul 2005 17:18:54 GMT, "S.Tobias"
<[email protected]> wrote:
They aren't the same; the difference is small but vital.

<snip explanation of lvalue definition differences between C90/C99>

Your explanation was excellent, but for the second time in this thread
you've misread the original article. Look at the specific paragraphs
referenced again...
Unfortunately, as
you and Netocrat have discussed at great length, IINM significantly
greater length than the scores if not hundreds of times this has been
discussed previously

Right, it's been a long and somewhat pedantic thread. With the aim
something useful be distilled from it, and hopefully it need not be
repeated, I've summarised what at the end of this thread I understand
the lvalue problem in the C99 standard to be here:

http://members.dodo.com.au/~netocrat/c/lvalue.html

If anyone has any comments, they are welcome to email me. Of course
they could also post a response here. My intention is to reduce
recurring discussion of the issue by providing a statement that can be
referred to. It would be good to know that the statement is commonly
agreed as accurate by regulars here.

Should sufficient people agree that the page is accurate, and that it's
appropriate to do so, I'll also post the reference on comp.std.c.

<snip rest>
 
S

Steve Summit

If a void pointer doesn't point to an object, then where does
it point to?

What is the sound of one hand clapping? :)

I haven't been following the whole thread, but to my mind saying
"a void pointer doesn't point to an object" is a lot like saying
"a const object can't be modified". Well, you *can* modify a
const object (or try to), but you'll need a cast, to get rid of
the constness so that the compiler won't complain about it.
Similarly, you can take a void pointer and pretend it points to
an object, and here you don't always even need an explicit cast,
because the compiler will perform the conversion implicitly if
you, for example, assign the void pointer to a variable of object
pointer type.

The analogy is far from perfect, of course, because trying to
modify a const object is usually cheating (else you wouldn't have
declared it const in the first place). Taking a void pointer,
on the other hand, and "pretending" that it points to an actual
object, is usually not cheating, because usually we're not
pretending -- we *know* that, just beneath the void * veneer,
the pointer actually does point to a real object.

(I suspect everyone understands this just fine, and that the
debate is one of those how-many-angels-can-dance-on-the-head-
of-a-pin ones having to do with excruciatingly close readings of
the Standard, and if so, sorry for restating the merely obvious.)

Steve Summit
(e-mail address removed)
 
L

lawrence.jones

Keith Thompson said:
So as far as ISO 1087 is concerned, a "definition" distinguishes the
defined term from other terms, but doesn't necessarily distinguish
things that meet the definition from things that don't.

Sigh.

So you don't like the definition of "definition"? :)

-Larry Jones

Hmm... That might not be politic. -- Calvin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,951
Messages
2,570,113
Members
46,698
Latest member
alexxx

Latest Threads

Top