is possible to build some pointer array?

A

Alan Balmer

Keith said:
malloc will return a void pointer so type cast it and assign it to
memo_index.
for (i=0;i<10;i++)
memo_index=(int *)malloc(10);
type casting depends on the way you want to use pointer.


No, no, no.

malloc() returns a result of type void*, which will be implicitly
converted to any pointer-to-object type. Casting the result is
unnecessary, and can mask certain errors such as forgetting to
"#include <stdlib.h>" or using a C++ compiler.

Then how we should assign the memo_index .
Is it like
memo_index=malloc(10);
then i am getting this warning
warning: assignment makes pointer from integer without a cast


I love it. You've just illustrated the error Keith was referring to.

#include <stdlib.h>
 
A

Alan Balmer

Yeah, but this is not only common, but standard practice when dealing
with networking code. Years ago I used to write code for communication
protocols and I used to extract data from packets byte-by-byte in for
loops. It's only 2 or 3 years ago that I started writing TCP/IP code
(libpcap etc..) that I noticed that people are using structs to extract
data form packets. Since it is so wide spread I didn't especially think
of it as 'clever' but just 'standard'.

It's workable, because there's an agreement between sender and
receiver. But it's not standard. There are useful conventions for
communication between different systems, but they are outside the
scope of c.l.c.
 
C

Chris Torek

(Actually #3 is an overstatement: they can have different sizes as
long as the "bigger" pointers can be stored in the "smaller" ones
temporarily without loss of information when converted back to the
"bigger" ones.)

Hmm, a lot of code I've seen make the assumption that 1==2.

I assume "1==2" is shorthand for some kind of reference to items 1
and 2 in Jack Klein's list, although I am not quite sure what. Still:
Especially TCP/IP libraries in Linux, Windows, BSD etc. that casts
a char* into structs to extract data from a packet.

It is worth noting two things about the BSD code and everything
derived from it (whether directly, as in the case of a number of
other TCP/IP implementations, or indirectly, as in the case of,
well, almost every remaining TCP/IP implementation :) ).

First, most of the code was written in the early 1980s, before
there was any C standard at all. So the overall design does not
conform well to the standards, for historical reasons. There have
been some attempts to bring the code into the 1990s (including some
on my part, back *in* the 1990s), but with limited success.

Second, the code is in fact *not* portable. Some of this was done
deliberately: the use of ntohl() and htonl(), for instance, is
often turned into a no-op on big-endian machines in the name of
performance. This is important because the VAX has a one megahertz
CPU, and thus no computer is faster than about 1 MHz. :)

(In other words, a lot of portability was sacrificed to the Little
Tin God of Efficiency. This may well have been the right decision
in 1983. It was, I think, wrong by 2003, if not earlier.)
If 1!=2, then you're saying that a void pointer should not ever point
to a struct. But this is how polymorphism is usually emulated in C.
Why, even malloc( ) returns a void pointer which can be used to point
to an area of memory to store a struct.

This is OK! It may help to use a little "ESP": Exaggeration of System
Parameters. Imagine for a moment that "void *" (and thus "char *" as
well, due to the "same representation" requirement for void* and char*)
each occupy one megabyte of data, while "struct S *" (for any S) uses
four bytes.

Will a four-byte "struct S *" always fit in a one-megabyte buffer?
(Sure!)

Will a one-megabyte "char *" or "void *" fit in a "struct S *"?
(Nope.) But if the four "important" bytes match up, that limited
subset of assignments *does* work:

struct S *orig;
void *tmp;
struct S *new;

orig = <some expression>;

tmp = orig; /* always works: copies 4 bytes into 1-MB buffer */

new = tmp; /* this works too: it copies the 4 "important" bytes back */

To make malloc() work, we just have to make sure that most of the
one-megabyte value is "unused", so that all the "good parts" fit:

tmp = malloc(sizeof(struct S)); /* sets all 1-MB bytes */

orig = tmp; /* copies 4 "important" bytes; works only if
the rest of the bytes really were unimportant */
Besides, aren't pointers just addresses into memory?

Pointers are typed, and have sizes. "Addresses" may or may not
have some other type and size.
Why would a CPU differentiate between structured and unstructured
bytes?

Consider the Cray or the Data General Eclipse (MV/10000). These
machines do not have 8-bit bytes as a "machine level" entity (with
a caveat for the Eclipse); instead, their CPUs address "words" --
64-bit words on the Cray, 16-bit words on the Eclipse. Word 0
contains 8 8-bit bytes (on the Cray) or 2 8-bit bytes (on the
Eclipse).

Most pointer types -- "int *", "struct S *", "double *", and so
on -- point to machine words. They need only the regular old
"machine word pointer" value that the hardware handles directly.
This points to 64 bits (on the Cray) or 16 bits (on the Eclipse).

The compiler-writers could have chosen to make CHAR_BIT 64 (on the
Cray) or 16 (on the Eclipse; the Eclipse has some extra features
that make this a particularly bad idea) -- but they chose instead
to make CHAR_BIT be 8. To do this, they had to make "char *"
(and thus "void *") "smuggle in" some extra bits, above and beyond
the "machine word" address.

On the Cray, with at least some C compilers, the extra bits are
stored near the high end of the machine address word. That is,
machine addresses 0, 1, 2, ... are represented as "byte address"
0, 1, 2, ..., so in order to identify "byte 3 of machine address
0", the needed three bits -- the ones that tell which 8-bit group
is to be used out of the 64-bit word -- are near the high end
of the address. Thus, bytes are addressed as: 0x000...0, 0x100...0,
0x200...0, 0x300...0, 0x400...0, 0x500...0, 0x600...0, 0x700...0,
0x000...1, 0x100...1, 0x200...1, and so on.

On the Eclipse, the hardware actually has support for "byte pointers".
The CPU has special instructions for converting "word pointers" to
"byte pointers" and vice versa. This "special instruction" is
actually just a one-bit shift, discarding the "I" -- indirect --
bit from the word address and introducing a byte-offset bit. So
on the Eclipse:

int *ip;
char *cp;
...
cp = malloc(N * sizeof(int));
ip = (int *)cp;

compiles to the same machine code as:

uint32_t ip, cp;
...
cp = malloc_equivalent(N * sizeof(int));
ip = cp >> 1;

Since malloc() actually returns "void *", malloc() on the Eclipse must
always return a "word-aligned" byte-pointer, whose low bit is 0, so
that "ip = cp >> 1" always discards a zero bit. That way, a later
call like:

cp = ip << 1;
free_equivalent(cp);

passes the correct number -- when ip is converted from a word
pointer to a byte pointer, the result is always word-aligned.

The old PR1ME (which may never have had an ANSI C compiler) had
32-bit "int *" machine-level pointers, and 48-bit "char *" pointers,
as all 32 bits were in use and -- as with the Cray and Eclipse --
the compiler-writers chose to make CHAR_BIT 8 anyway. This meant
the compiler needed extra bits in a "char *", in order to pick out
which byte you wanted, and that required an extra 16 bits.
 
M

Mark McIntyre

On 8 Nov 2005 23:19:23 -0800, in comp.lang.c ,
Then how we should assign the memo_index .
Is it like
memo_index=malloc(10);
then i am getting this warning
warning: assignment makes pointer from integer without a cast


Then you're doing one of two things:
1) not #including stdlib.h
2) using a C++ compiler

Its vaguely possible you're using a pre-ansi compiler but thats less
likely since it would have to be 25 years old now.
 
M

Mark McIntyre

Hmm, a lot of code I've seen make the assumption that
(pointers all have the same size)
. Especially
TCP/IP libraries in Linux, Windows, BSD etc. that casts a char* into
structs to extract data from a packet.

They're quite free to do this, on any given implementation. One
assumes that the writers of this code know their target hardware well
enough to be *absolutely sure* this will always be true.

However their code won't port to different hardware, or will port
badly, or will apparently port and then mysteriously break. .
you're saying that a void pointer should not ever point
to a struct.

Not portably.
But this is how polymorphism is usually emulated in C.

and this is heavily platform specific and nonportable.
Why, even malloc( ) returns a void pointer which can be used to point
to an area of memory to store a struct.

Malloc is a special case. Its /required/ to work like this
Besides, aren't pointers just addresses into memory? Why would a CPU
differentiate between structured and unstructured bytes?

Heavens.
 
J

Jordan Abel

On 8 Nov 2005 23:19:23 -0800, in comp.lang.c ,
Then how we should assign the memo_index .
Is it like
memo_index=malloc(10);
then i am getting this warning
warning: assignment makes pointer from integer without a cast


Then you're doing one of two things:
1) not #including stdlib.h
2) using a C++ compiler


The second would cause a vastly different diagnostic.
Its vaguely possible you're using a pre-ansi compiler but thats less
likely since it would have to be 25 years old now.

25 years since 1989? I think you're off by a decade - it's been 25 years
since _1980_.

Still shoulda included stdlib.h - which would include the line
char *malloc ();

char * is not an integer type, of course.
 
M

Mark McIntyre

But I don't understand how malloc can be made to work with these rules.

Thats not for us to understand. Any compiler that conforms to the
standard /must/ provide malloc which matches these rules. If it can't
then it isn't a C compiler.
I don't see how malloc can be useful if you can't assign a void pointer
to a struct pointer.

A pointer returned by malloc is guaranteed to be acceptable for
whatever type you need. How malloc manages that is its business. You'd
have to ask in hardware-specific groups to find out how its done on
the different architectures.
 
D

Default User

Mark said:
On 8 Nov 2005 23:19:23 -0800, in comp.lang.c ,
Then how we should assign the memo_index .
Is it like
memo_index=malloc(10);
then i am getting this warning
warning: assignment makes pointer from integer without a cast


Then you're doing one of two things:
1) not #including stdlib.h
2) using a C++ compiler


Not to wander too off-topic, but that's not a typical C++ diagnostic
for this case. You'd expect to see "Conversion from 'void*' to pointer
to non-'void' requires an explicit cast" or something of that sort. The
int to void* implies implicit declaration, which is not allowed in C++.



Brian
 
P

pete

Mark said:
On 8 Nov 2005 22:35:57 -0800, in comp.lang.c , "(e-mail address removed)"


Not portably.

I don't see anything wrong with a pointer to void
having a value which compares equal to the address of a struct,
but I don't think that's quite the same thing as pointing
to a struct.
 
M

Mark McIntyre

The second would cause a vastly different diagnostic.

There's no way to know, since
a) C++ is offtopic here and
b) an implemetnation can emit whatever diagnostics it wants to, when
it encounters a bug.
 
J

Jordan Abel

There's no way to know, since
a) C++ is offtopic here and
b) an implemetnation can emit whatever diagnostics it wants to, when
it encounters a bug.

Yes but it would be nonsense to claim "from integer" when it's in fact
an illegal conversion from [c++] void * or [pre-ansi] char *
 
S

slebetman

pete said:
I don't see anything wrong with a pointer to void
having a value which compares equal to the address of a struct,
but I don't think that's quite the same thing as pointing
to a struct.

Richard Bos said this IS portable:
A void pointer is guaranteed to be able to contain any other kind of object pointer.

A void pointer can point to anything. But a struct pointer may not be
able to point to a void object except in special cases like an object
generated by malloc which is word aligned.

I think I understand now. Especially since a lot of CPUs that I design
for fun don't have byte addressing ;-)

To sum up:

1. Not all pointers are created equal.
2. Void and char pointers are compatible due to historical reasons.
3. Void pointers can point to anything.
4. Typed pointers can point to void objects only if the object is
properly aligned to not need the extra information contained in the
void pointer. That is, it only needs the 'base address'.

I've been writing code for years on various 8, 16 & 32 bit platforms
but never noticed this subtlety. Anything else I'm missing?
 
S

slebetman

Alan said:
It's workable, because there's an agreement between sender and
receiver. But it's not standard. There are useful conventions for
communication between different systems, but they are outside the
scope of c.l.c.

I think it's workable because Unix compilers supports this more than
anything else. As someone stated somewhere in this thread, most systems
inherited TCP/IP code from BSD and the BSD stack was written in the
80s. And it was also said that attempts to modernise this code was not
that succesfull. So it's mostly for historical reasons. And yes, I
know, such reasons are not really on topic here.

I have seen TCP/IP code which does not do this though (extract data via
struct pointers). They are usually written for 8 bit micros & embedded
systems.
 
P

pete

Richard Bos said this IS portable:


A void pointer can point to anything.

It depends on what you mean by "point".
A pointer to void, can hold the address of any object,
but whether or not that's the same thing as "pointing"
is debatable.

http://groups.google.com/group/comp.lang.c/msg/10830a15ee7c882d

In the above referenced post, quotes Douglas A. Gwyn
as saying "A void* doesn't point to *any* object!"

Doug can be wrong, but Doug's name is printed
in K&R2 and also on the C89 last public draft,
so he's just not any Bozo.
 
K

Keith Thompson

A void pointer can point to anything. But a struct pointer may not be
able to point to a void object except in special cases like an object
generated by malloc which is word aligned.

I think I understand now. Especially since a lot of CPUs that I design
for fun don't have byte addressing ;-)

To sum up:

1. Not all pointers are created equal.
2. Void and char pointers are compatible due to historical reasons.
3. Void pointers can point to anything.
4. Typed pointers can point to void objects only if the object is
properly aligned to not need the extra information contained in the
void pointer. That is, it only needs the 'base address'.

I've been writing code for years on various 8, 16 & 32 bit platforms
but never noticed this subtlety. Anything else I'm missing?

There is no such thing as a "void object".

This is more correctly expressed in terms of conversions between
pointer types.

C99 6.3.2.3 says:

A pointer to void may be converted to or from a pointer to any
incomplete or object type. A pointer to any incomplete or object
type may be converted to a pointer to void and back again; the
result shall compare equal to the original pointer.

[...]

A pointer to an object or incomplete type may be converted to a
pointer to a different object or incomplete type. If the resulting
pointer is not correctly aligned for the pointed-to type, the
behavior is undefined. Otherwise, when converted back again, the
result shall compare equal to the original pointer. When a pointer
to an object is converted to a pointer to a character type, the
result points to the lowest addressed byte of the
object. Successive increments of the result, up to the size of the
object, yield pointers to the remaining bytes of the object.
 
S

slebetman

Keith said:
There is no such thing as a "void object".

I know that. But I didn't want to write "an area of memory accessible
via a void pointer".
OK, but my understanding of this is basically correct rignt?
 
S

slebetman

pete said:
It depends on what you mean by "point".
A pointer to void, can hold the address of any object,
but whether or not that's the same thing as "pointing"
is debatable.

http://groups.google.com/group/comp.lang.c/msg/10830a15ee7c882d

In the above referenced post, quotes Douglas A. Gwyn
as saying "A void* doesn't point to *any* object!"

Doug can be wrong, but Doug's name is printed
in K&R2 and also on the C89 last public draft,
so he's just not any Bozo.

Oh wow. Didn't know there was such a long discussion on the meaning of
'point'. I'm talking form a programmer's perspective: pointing is what
pointers does. That is, 'point' is telling me where in memory something
is as oposed to an 'instance' which tells me what value that something
contains.

Anyway.. I defer to that thread on the exact definition of 'point'. But
what I meant simply was the address of an object.
 
P

pete

Anyway.. I defer to that thread on the exact definition of 'point'.
But
what I meant simply was the address of an object.

OK. I'll pedant some more.

More better to say that they have the same representation.

"Compatible" is a technical term in C.

C99
6.2.7 Compatible type and composite type
[#1] Two types have compatible type if their types are the
same.

.... to any object, to any byte in any object,
to one past the last byte of an object,
but not to anywhere else, including not to a function.

I read your discussion with Kieth.
There's no way to get a "void object" that isn't
properly aligned, so the "only if" part isn't necessary.
 
O

Old Wolf

Yeah, but this is not only common, but standard practice when
dealing with networking code. Years ago I used to write code
for communication protocols and I used to extract data from
packets byte-by-byte in for loops. It's only 2 or 3 years ago
that I started writing TCP/IP code (libpcap etc..) that I
noticed that people are using structs to extract data form
packets. Since it is so wide spread I didn't especially think
of it as 'clever' but just 'standard'.

This is not portable, because different compilers might use a
different memory layout for the same struct.

However it is extremely convenient and leads to shorter and
easier-to-read code (hence its popularity, I guess).

Usually this technique is done with "packed" structs -- a common
compiler extension that builds a struct with no padding. Then
the code will be reliable, assuming that the data types always
have the same width of course!

Good programmers will include a few extra compile-time
checks, to make sure the structure size is what they expect,
and perhaps also that the member offsets (using the offsetof()
macro) are what they expect.

Also: note that pointing a struct pointer into a block of
chars may fail because of alignment -- the code should
either memcpy the chars into the struct, or make sure that
the chars are correctly aligned (eg. if they were allocated
by malloc).
 

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
474,171
Messages
2,570,935
Members
47,472
Latest member
KarissaBor

Latest Threads

Top