By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,315 Members | 1,736 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,315 IT Pros & Developers. It's quick & easy.

Pointer initialization.

P: n/a

Hello kind people.

Can someone explain please the following code?

/* Create Storage Space For The Texture */
AUX_RGBImageRec *TextureImage[1]; /* Line 1*/
/* Set The Pointer To NULL */
memset(TextureImage,0,sizeof(void *)*1); /* Line 2*/

According to my knowledge in the first line
the TextureImage variable is declared as
an array of one pointer to AUX_RGBImageRec.

Here is my question.
I don't understand the second line at all.
Especially the sizeof(void *) *1 thing.
What does it mean?

The initialization of the array of Pointer
could be better like this
AUX_RGBImageRec *TextureImage[1] = {NULL};
Right? It has the same effect?

(I know the distinction, but let's assume
that NULL and 0 is translated as the same
thing for the moment.)

Many thanks for any help.

--
tuko the ugly.

Nov 14 '05 #1
Share this Question
Share on Google+
35 Replies


P: n/a
tuko wrote:

Can someone explain please the following code?

/* Create Storage Space For The Texture */
AUX_RGBImageRec *TextureImage[1]; /* Line 1*/
/* Set The Pointer To NULL */
memset(TextureImage,0,sizeof(void *)*1); /* Line 2*/

According to my knowledge in the first line
the TextureImage variable is declared as
an array of one pointer to AUX_RGBImageRec.


It's stupid nonsense, to all practical purposes. Trust yourself
and write better and clearer code. What you probably want is:

AUX_RGBImageRec *TextureImage;
TextureImage = NULL;

without the misleading comments.

--
"The most amazing achievement of the computer software industry
is its continuing cancellation of the steady and staggering
gains made by the computer hardware industry..." - Petroski

Nov 14 '05 #2

P: n/a
tuko <tu**@away.com> writes:
Can someone explain please the following code?

/* Create Storage Space For The Texture */
AUX_RGBImageRec *TextureImage[1]; /* Line 1*/
/* Set The Pointer To NULL */
memset(TextureImage,0,sizeof(void *)*1); /* Line 2*/
The second line is problematic (see below) and doesn't do what the
comment suggests.
According to my knowledge in the first line
the TextureImage variable is declared as
an array of one pointer to AUX_RGBImageRec.
Yes.
Here is my question.
I don't understand the second line at all.
Especially the sizeof(void *) *1 thing.
What does it mean?
It yields the size of a generic object pointer, also known as pointer to
void. Multiplying `sizeof (void *)' with 1 has no effect.

The `memset' call therefore sets `sizeof (void *)' consecutive bytes,
starting from the address `TextureImage', to zero (i.e. it sets all bits
of these bytes to zero).
The initialization of the array of Pointer
could be better like this
AUX_RGBImageRec *TextureImage[1] = {NULL};
Right?
Yes. Alternatively, if an assignment instead of an initialization is
desired,

TextureImage [0] = NULL;

would work.
It has the same effect?
Well, no, the original code doesn't necessarily work correctly. It has
two problems. First of all, the `memset' call sets all bits to zero,
but that is not necessarily the correct representation of a null
pointer. OTOH, initialization with NULL or assignment of NULL always
sets the pointer to a null pointer, even if the internal representation
of a null pointer is /not/ all-bits-zero.

Secondly, `sizeof (void *)' (the size of a generic object pointer) need
not be the same as `sizeof (AUX_RGBImageRec *)' (the size of a pointer
to `AUX_RGBImageRec'), so the `memset' call doesn't even get the size
right.
(I know the distinction, but let's assume
that NULL and 0 is translated as the same
thing for the moment.)


`NULL' is allowed to expand to `0', and wherever `NULL' is correct,
writing `0' instead is correct as well. In a context where a pointer is
needed, `0' is treated as a null pointer constant, not as the integer 0.

Martin
--
,--. Martin Dickopp, Dresden, Germany ,= ,-_-. =.
/ ,- ) http://www.zero-based.org/ ((_/)o o(\_))
\ `-' `-'(. .)`-'
`-. Debian, a variant of the GNU operating system. \_/
Nov 14 '05 #3

P: n/a
Martin Dickopp wrote:

[ snip ]

Secondly, `sizeof (void *)' (the size of a generic object pointer) need
not be the same as `sizeof (AUX_RGBImageRec *)' (the size of a pointer
to `AUX_RGBImageRec'), so the `memset' call doesn't even get the size
right.


Are you saying that `sizeof (AUX_RGBImageRec *) != sizeof (void *)'?

So, `AUX_RGBImageRec *' could _never_ be used inside the
compare function of `qsort(3C)' since its pointer size may
be different than the size of a `void *'?!!!
Stephen
Nov 14 '05 #4

P: n/a
Stephen L. wrote:
Martin Dickopp wrote:

[ snip ]

Secondly, `sizeof (void *)' (the size of a generic object pointer) need
not be the same as `sizeof (AUX_RGBImageRec *)' (the size of a pointer
to `AUX_RGBImageRec'), so the `memset' call doesn't even get the size
right.

Are you saying that `sizeof (AUX_RGBImageRec *) != sizeof (void *)'?


I might be.

So, `AUX_RGBImageRec *' could _never_ be used inside the
compare function of `qsort(3C)' since its pointer size may
be different than the size of a `void *'?!!!


It can be used even if they have different sizes. Or do you
think that you cannot pass a char to a function which expects
an int?

--
Thomas

Nov 14 '05 #5

P: n/a
"Stephen L." <sd*********@cast-com.net> writes:
Martin Dickopp wrote:
Secondly, `sizeof (void *)' (the size of a generic object pointer) need
not be the same as `sizeof (AUX_RGBImageRec *)' (the size of a pointer
to `AUX_RGBImageRec'), so the `memset' call doesn't even get the size
right.
Are you saying that `sizeof (AUX_RGBImageRec *) != sizeof (void *)'?


I'm not saying that these sizes /must/ be different, but that they /can/
be different.
So, `AUX_RGBImageRec *' could _never_ be used inside the
compare function of `qsort(3C)' since its pointer size may
be different than the size of a `void *'?!!!


You can safely cast the pointers passed to the comparison function back
to the appropriate type (i.e. `AUX_RGBImageRec **' if you're sorting an
array of `AUX_RGBImageRec' pointers, or `AUX_RGBImageRec *' if you're
sorting an array of `AUX_RGBImageRec' objects). But that doesn't mean
that the pointer types have to have the same size. If the pointer types
have different representations, the cast converts the bit patterns as
needed.

Martin
--
,--. Martin Dickopp, Dresden, Germany ,= ,-_-. =.
/ ,- ) http://www.zero-based.org/ ((_/)o o(\_))
\ `-' `-'(. .)`-'
`-. Debian, a variant of the GNU operating system. \_/
Nov 14 '05 #6

P: n/a


tuko wrote:

Hello kind people.

Can someone explain please the following code?

/* Create Storage Space For The Texture */
AUX_RGBImageRec *TextureImage[1]; /* Line 1*/
/* Set The Pointer To NULL */
memset(TextureImage,0,sizeof(void *)*1); /* Line 2*/

According to my knowledge in the first line
the TextureImage variable is declared as
an array of one pointer to AUX_RGBImageRec.

Here is my question.
I don't understand the second line at all.
Especially the sizeof(void *) *1 thing.
What does it mean?

The initialization of the array of Pointer
could be better like this
AUX_RGBImageRec *TextureImage[1] = {NULL};
Right? It has the same effect?

Possibly not have the same effect.
Your version will set the the array element to NULL.
The memset version is flawed. All-bits-zero
in a pointer object is not guaranteed to represent
a null pointer.

In addition, I fail to envision why the code declares
TextureImage as an array of 1. If there is only one
element you might as well declare it:
AUX_RGBImageRec *TextureImage = NULL;
One might declared an array of 1 with the intention of
playing allocation tricks, i.e. the last member of a
struct. This is covered in the faq. I prefer to declare:
AUX_RGBImageRec **TextureImage
and dynamically allocate the needed number of pointers.

Example:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef char AUX_RGBImageRec; /* For an example */

int main(void)
{
AUX_RGBImageRec *pTextureImage = NULL;
AUX_RGBImageRec **ppTextureImage = NULL;
int i;
char *string[] = {"George Washington",
"Abe Lincoln",
"George Bush"};

pTextureImage = string[0];
printf("pTextureImage = \"%s\"\n\n",pTextureImage);

ppTextureImage = malloc((
sizeof *ppTextureImage)*(sizeof string/sizeof *string));
if(ppTextureImage)
{
puts("Some U,S. Presidents:");
for(i = 0;i < sizeof string/sizeof *string; i++)
{
ppTextureImage[i] = string[i];
printf("ppTextureImage[%d] = \"%s\"\n",i,ppTextureImage[i]);
}
free(ppTextureImage);
}
else puts("Memory allocation failure with ppTextureImage");
printf("sizeof(pTextureImage) = %u\nsizeof(void *) = %u\n",
sizeof pTextureImage, sizeof(void *));
return 0;
}

-
Al Bowers
Tampa, Fl USA
mailto: xa******@myrapidsys.com (remove the x to send email)
http://www.geocities.com/abowers822/

Nov 14 '05 #7

P: n/a
In article <c8**********@nic.grnet.gr>, tuko <tu**@away.com> wrote:
Hello kind people.

Can someone explain please the following code?

/* Create Storage Space For The Texture */
AUX_RGBImageRec *TextureImage[1]; /* Line 1*/
/* Set The Pointer To NULL */
memset(TextureImage,0,sizeof(void *)*1); /* Line 2*/

According to my knowledge in the first line
the TextureImage variable is declared as
an array of one pointer to AUX_RGBImageRec.

Here is my question.
I don't understand the second line at all.
Especially the sizeof(void *) *1 thing.
What does it mean?

The initialization of the array of Pointer
could be better like this
AUX_RGBImageRec *TextureImage[1] = {NULL};
Right? It has the same effect?


1. Yes.
2. It has the same effect as what the memset intends to do. The memset
is not portable and might go completely wrong, the corrected version
will always work. (void* doesn't necessarily have the same size as
AUX_RGBImageRec*, whatever an AUX_RGBImageRec is, and setting the
individual bytes in the representation of a pointer to zero doesn't
necessarily change the pointer to a null pointer as intended).
Nov 14 '05 #8

P: n/a
In article <40***************@cast-com.net>,
"Stephen L." <sd*********@cast-com.net> wrote:
Martin Dickopp wrote:

[ snip ]

Secondly, `sizeof (void *)' (the size of a generic object pointer) need
not be the same as `sizeof (AUX_RGBImageRec *)' (the size of a pointer
to `AUX_RGBImageRec'), so the `memset' call doesn't even get the size
right.


Are you saying that `sizeof (AUX_RGBImageRec *) != sizeof (void *)'?

So, `AUX_RGBImageRec *' could _never_ be used inside the
compare function of `qsort(3C)' since its pointer size may
be different than the size of a `void *'?!!!


When you pass a pointer to qsort, you cast it to void*. Same thing as
when you pass a short to a function that has a long argument.
Nov 14 '05 #9

P: n/a
>In article <40***************@cast-com.net>
"Stephen L." <sd*********@cast-com.net> wrote:
Are you saying that `sizeof (AUX_RGBImageRec *) != sizeof (void *)'?
Possibly, yes.
So, `AUX_RGBImageRec *' could _never_ be used inside the
compare function of `qsort(3C)' since its pointer size may
be different than the size of a `void *'?!!!

In article <news:ch*********************************@slb-newsm1.svr.pol.co.uk>
Christian Bau <ch***********@cbau.freeserve.co.uk> writes:When you pass a pointer to qsort, you cast it to void*. Same thing as
when you pass a short to a function that has a long argument.


Indeed. It might be worth expanding on this, though.

Suppose you have a qsort-callable function:

/* compare left- and right-side "zorg"s */
int zorgcompare(const void *l0, const void *r0) {
const struct zorg *l = l0; /* to sort an array of "zorg"s */
const struct zorg *r = r0; /* if array of ptrs, make these "**" */
... code to compare them ...
return whatever;
}

Now let us also suppose you have an unusual machine in which "struct
zorg *" is (say) four bytes long, but "void *" is 1048576 bytes
long (one megabyte). (Outrageous? Perhaps, but "Exaggeration of
System Parameters" is quite a good way of figuring out whether
something will break under stress. Apply a little ESP in your
daily life as an engineer or programmer!) When you call qsort()
to sort an array of "struct zorg" you do this:

struct zorg the_array[N];
... fill in the_array[i] ...
/*
* The "void *" conversion happens even without the cast, and
* normally I suggest leaving it out, but it is here to show
* the explicit conversion. The value of n here is in [0..N),
* i.e., no more than the upper limit N.
*/
qsort((void *)&the_array[0], n, sizeof(struct zorg), zorgcompare);

Or, if zorgcompare() uses "const struct zorg **", you do this:

struct zorg *the_array[N];
... set up the_array[i], where i is in [0..n) and n <= N ...
... fill in the_array[i][0] (typically via the_array[i]->field
rather than the_array[i][0].field) ...
qsort((void *)&the_array[0], n, sizeof(struct zorg *), zorgcompare);

In each case, you take a four-byte "struct zorg *" or "struct zorg **"
and convert it to one of these 1-megabyte-wide "void *"s.

Clearly, four bytes fit within a million.

Now qsort() does its thing, no doubt using "const char *" internally
because arithmetic is forbidden on "void *" pointers, on the bytes
that make up "the_array". As qsort() comes up with pointers pointing
to (each first byte of) the_array[i], it passes them, in "void *"
format -- one megabyte each -- to zorgcompare().

It is zorgcompare()'s job to extract the four *useful* bytes out
of the one-million, and use those to compare the desired "zorg"s.
Clearly, if the four bytes have a well-defined location within the
megabyte, the compiler will be able to pluck them out and use them.

In other words, it all works, despite the fact that, on this odd
machine, "void *" is ENORMOUS compared to other pointer types.

"But isn't this inefficient?" Yes, it is horrendously inefficient,
which is why real machines never use one-megabyte "void *" pointers.
You can trust the folks who write compilers to figure out some way
to make "void *" reasonably efficient on your machine. Obviously
"one megabyte" is not required, and chances are "four bytes" will
do the trick just fine, and parameter-passing will be efficient.

But if you have a sufficiently oddball machine, "void *" really
MIGHT be slightly less efficient than "struct zorg *" -- and if
your compiler writers are not supremely clever, AND you have this
weird kind of computer, AND "void *" parameter passing is noticeably
slow, AND all the parameter-passing involved in qsort() is making
your program run unacceptably slowly -- well, if all of these
amazing coincidences *all* turn out to be the case at once, *then*
you might want to use something other than qsort() and its
"void *"s. Until that proves to be the case, though, you might as
well just write the clearest, simplest code you can. Chances are,
any problems you run into will not have anything to do with
"void *" being inefficient.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #10

P: n/a
Christian Bau wrote:
In article <40***************@cast-com.net>,
"Stephen L." <sd*********@cast-com.net> wrote:

Martin Dickopp wrote:

[ snip ]

Secondly, `sizeof (void *)' (the size of a generic object pointer) need
not be the same as `sizeof (AUX_RGBImageRec *)' (the size of a pointer
to `AUX_RGBImageRec'), so the `memset' call doesn't even get the size
right.


Are you saying that `sizeof (AUX_RGBImageRec *) != sizeof (void *)'?

So, `AUX_RGBImageRec *' could _never_ be used inside the
compare function of `qsort(3C)' since its pointer size may
be different than the size of a `void *'?!!!

When you pass a pointer to qsort, you cast it to void*. Same thing as
when you pass a short to a function that has a long argument.


No. The whole point of C90 prototypes is to clue the compiler so
that it can do the conversions for you. You need not (and should
not) cast your arguments to functions to match the function's
parameters. The compiler will do it for you. math.h declares the
prototype..

double sqrt(double x);

...so that when you call 'sqrt(3);' with an int argument, the
compiler will figure it out and pass 3.0 instead. Really.

--
Joe Wright mailto:jo********@comcast.net
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 14 '05 #11

P: n/a
Chris Torek wrote:
In article <40***************@cast-com.net>
"Stephen L." <sd*********@cast-com.net> wrote:
Are you saying that `sizeof (AUX_RGBImageRec *) != sizeof (void *)'?
Possibly, yes.
So, `AUX_RGBImageRec *' could _never_ be used inside the
compare function of `qsort(3C)' since its pointer size may
be different than the size of a `void *'?!!!

[ snip'd - example code about 1meg void pointer type and `qsort()' ]
....

"The same is true in C. While things may be big and small,
pointers come in one size (relatively small).[1]"
^^^^^^^^ ^^^^ ^^ ^^^ ^^^^

....
This is a sentence from the 5th paragraph after
illustration 13.1A from ->

http://www.oreilly.com/catalog/pcp3/chapter/ch13.html

If anyone believes that pointers to two different
types (even if one of the types is the `void' type)
are not the _same_ size; could be _different_ size(s)...

....well, don't make me come over there... :) :) :)

Really, though, the above link is _really_ good
reading to anyone interested in another viewpoint
on pointer to type(s) in the C language (I'm not
trying to insult anybody), and certainly authoritative.
Sincerely,

Stephen
Nov 14 '05 #12

P: n/a
"Stephen L." <sd*********@cast-com.net> writes:
Chris Torek wrote:
>In article <40***************@cast-com.net>
> "Stephen L." <sd*********@cast-com.net> wrote:
>> Are you saying that `sizeof (AUX_RGBImageRec *) != sizeof (void *)'?
Possibly, yes.
>> So, `AUX_RGBImageRec *' could _never_ be used inside the
>> compare function of `qsort(3C)' since its pointer size may
>> be different than the size of a `void *'?!!!

[ snip'd - example code about 1meg void pointer type and `qsort()' ]

"The same is true in C. While things may be big and small,
pointers come in one size (relatively small).[1]"
^^^^^^^^ ^^^^ ^^ ^^^ ^^^^
This is a sentence from the 5th paragraph after
illustration 13.1A from ->

http://www.oreilly.com/catalog/pcp3/chapter/ch13.html


The footnote [1] in the very same document (which you haven't quoted)
already clarifies that the statement isn't true.
If anyone believes that pointers to two different
types (even if one of the types is the `void' type)
are not the _same_ size; could be _different_ size(s)...

...well, don't make me come over there... :) :) :)
Don't know what you mean by that, but two pointers to different types
can certainly have different sizes.
Really, though, the above link is _really_ good reading
Well, after quickly skimming the document I found some things I don't
like stylistically (per-C89 definition of `main', return-statement
expression in parentheses), some things which are confusing (it is said
that `NULL' is defined in <locale.h>, but <stddef.h> isn't mentioned;
yet the example programs don't include <locale.h>), and some things
which are wrong (use of the word "illegal" where "invalid" is meant;
"pointers come in one size").
to anyone interested in another viewpoint
on pointer to type(s) in the C language (I'm not
trying to insult anybody), and certainly authoritative.


The only /authoritative/ document about the C language is the
/standard/.

Martin
--
,--. Martin Dickopp, Dresden, Germany ,= ,-_-. =.
/ ,- ) http://www.zero-based.org/ ((_/)o o(\_))
\ `-' `-'(. .)`-'
`-. Debian, a variant of the GNU operating system. \_/
Nov 14 '05 #13

P: n/a
Martin Dickopp wrote:
"The same is true in C. While things may be big and small,
pointers come in one size (relatively small).[1]"
^^^^^^^^ ^^^^ ^^ ^^^ ^^^^
This is a sentence from the 5th paragraph after
illustration 13.1A from ->

http://www.oreilly.com/catalog/pcp3/chapter/ch13.html
The footnote [1] in the very same document (which you haven't quoted)
already clarifies that the statement isn't true.


The footnote indicates that some platforms provide
non-standard extensions to the C language to overcome
deficiencies/quirks for that platform, and to make such
a platform more usable than it would be without the
extension(s). Why should I care, as a C programmer,
if a pointer needs to be NEAR or FAR? The C language
implementation on that platform should do that for me.
We're talking modern optimizing compilers, not some
implementation from the 80's with one foot still in
assembly language.

Also, we were talking specifically about the size of
pointers to two different _types_ being the same size,
even if one of the types was the `void' type.
If anyone believes that pointers to two different
types (even if one of the types is the `void' type)
are not the _same_ size; could be _different_ size(s)...

...well, don't make me come over there... :) :) :)
Don't know what you mean by that, but two pointers to different types
can certainly have different sizes.


It's a Dilbert reference, meant in a friendly humorous way...
Really, though, the above link is _really_ good reading
Well, after quickly skimming the document I found some things I don't
like stylistically (per-C89 definition of `main', return-statement
expression in parentheses), some things which are confusing (it is said
that `NULL' is defined in <locale.h>, but <stddef.h> isn't mentioned;
yet the example programs don't include <locale.h>), and some things
which are wrong (use of the word "illegal" where "invalid" is meant;
"pointers come in one size").


[ snips ]

The only /authoritative/ document about the C language is the
/standard/.


On that I agree, but even the "The C Programming Language"
had errata and style points that not everyone agreed with.
However, those issues had little impact on the significance
of the material presented in the book.

If the "standard" were all people needed to gain an
understanding of a language, publishers be'd out of
business in no time.
Just my point of view...

Stephen
Nov 14 '05 #14

P: n/a
In article <40***************@cast-com.net>,
"Stephen L." <sd*********@cast-com.net> wrote:
Chris Torek wrote:
In article <40***************@cast-com.net>
"Stephen L." <sd*********@cast-com.net> wrote:
> Are you saying that `sizeof (AUX_RGBImageRec *) != sizeof (void *)'?


Possibly, yes.
> So, `AUX_RGBImageRec *' could _never_ be used inside the
> compare function of `qsort(3C)' since its pointer size may
> be different than the size of a `void *'?!!!

[ snip'd - example code about 1meg void pointer type and `qsort()' ]
...

"The same is true in C. While things may be big and small,
pointers come in one size (relatively small).[1]"
^^^^^^^^ ^^^^ ^^ ^^^ ^^^^

...
This is a sentence from the 5th paragraph after
illustration 13.1A from ->

http://www.oreilly.com/catalog/pcp3/chapter/ch13.html

If anyone believes that pointers to two different
types (even if one of the types is the `void' type)
are not the _same_ size; could be _different_ size(s)...

...well, don't make me come over there... :) :) :)

Really, though, the above link is _really_ good
reading to anyone interested in another viewpoint
on pointer to type(s) in the C language (I'm not
trying to insult anybody), and certainly authoritative.


If you quoted it correctly, then it is certainly not authoritative.
Nov 14 '05 #15

P: n/a
"Stephen L." <sd*********@cast-com.net> writes:
Martin Dickopp wrote:
> "The same is true in C. While things may be big and small,
> pointers come in one size (relatively small).[1]"
> ^^^^^^^^ ^^^^ ^^ ^^^ ^^^^
> This is a sentence from the 5th paragraph after
> illustration 13.1A from ->
>
> http://www.oreilly.com/catalog/pcp3/chapter/ch13.html
The footnote [1] in the very same document (which you haven't quoted)
already clarifies that the statement isn't true.


The footnote indicates that some platforms provide
non-standard extensions to the C language to overcome
deficiencies/quirks for that platform, and to make such
a platform more usable than it would be without the
extension(s). Why should I care, as a C programmer,
if a pointer needs to be NEAR or FAR?


The footnote, as I understand it, gives an example of a platform where
even in a standard C implementation (i.e. no extensions), pointers of
two different sizes exist, namely 16 bit object pointers and 32 bit
function pointers or vice versa.
The C language implementation on that platform should do that for me.
It does, and to do so, it introduces object and function pointers of
different size.
Also, we were talking specifically about the size of
pointers to two different _types_ being the same size,
even if one of the types was the `void' type.


If the intention of the document is to claim that all object pointers
have the same size, then the document is wrong in this regard. The
standard simply doesn't require it.

Martin
--
,--. Martin Dickopp, Dresden, Germany ,= ,-_-. =.
/ ,- ) http://www.zero-based.org/ ((_/)o o(\_))
\ `-' `-'(. .)`-'
`-. Debian, a variant of the GNU operating system. \_/
Nov 14 '05 #16

P: n/a
In article <40***************@cast-com.net>,
Stephen L. <sd*********@cast-com.net> wrote:
Martin Dickopp wrote:

If anyone believes that pointers to two different
types (even if one of the types is the `void' type)
are not the _same_ size; could be _different_ size(s)...

From the C99 Standard. Section 6.2.5.26

A pointer to void shall have the same representation and alignment
requirements as a pointer to a character type. Similarly, pointers to
qualified or unqualified versions of compatible types shall have the same
representation and alignment requirements. All pointers to structure
types shall have the same representation and alignment requirements as
each other. All pointers to union types shall have the same
representation and alignment requirements as each other. Pointers to
other types need not to have the same representation and alignment
requirements.

This spells out that pointers to two different types need not be the same
size unless they are specified to be the same representation in the
preceding paragraph from the standard.

Kevin.

Nov 14 '05 #17

P: n/a
Kevin Bagust wrote:

In article <40***************@cast-com.net>,
Stephen L. <sd*********@cast-com.net> wrote:
Martin Dickopp wrote:

> If anyone believes that pointers to two different
> types (even if one of the types is the `void' type)
> are not the _same_ size; could be _different_ size(s)...


From the C99 Standard. Section 6.2.5.26

A pointer to void shall have the same representation and alignment
requirements as a pointer to a character type. Similarly, pointers to
qualified or unqualified versions of compatible types shall have the same
representation and alignment requirements. All pointers to structure
types shall have the same representation and alignment requirements as
each other. All pointers to union types shall have the same
representation and alignment requirements as each other. Pointers to
other types need not to have the same representation and alignment
requirements.

This spells out that pointers to two different types need not be the same
size unless they are specified to be the same representation in the
preceding paragraph from the standard.

Kevin.


Yes, I _just_ found that reading my draft version
of the standard (there's more than just that paragraph).
The text doesn't actually use the word "size",
but you're making that connection and the phrase
"same representation", correct?

I always though of a `void *' as a generic pointer type,
however, the last sentence implies that there are
pointers which may not be contained in a `void *'.

Ignoring the alignment requirements parts of the text,
a function pointer comes to mind (on some architectures)
that may be represented differently. But what does
that mean? Does it mean its size is different from that
of a `char *', or does it mean its value is interpreted
_differently_ (maybe the components of the address
it represents are in a different order or scale then the
components for a `char *'). Or does it mean both.

I'm not entirely convinced that their intentional
use of the phrase "same representation" includes
a pointer's size as well. A pointer type of a
different _size_, well, would be a whole _new_
pointer type, I believe.

What I read is that the standard is trying to address
a pointer's access - read/write or execute.
A function pointer (having an `execute' attribute)
does not have to have the same representation as
a `char *' (having read/write access). The
standard doesn't have to differentiate between the
two, either, or warn if a function pointer is
dereferenced as a `char *'.

My understanding (aside from all of the alignment
language) is that pointers of the same attribute have
compatible access. All function pointers (containing
a valid function pointer) can be executed, all
"read/write" pointers can be read/wrote. But, if
you put a function pointer into a `char *' and
dereference it, the standard (IMHO) is saying
that it doesn't have to point to the binary
value of the start of your function. The pointer
value could be interpreted in a completely
different way as an access pointer. Likewise,
converting a `char *', pointing to valid
machine instructions, to a function *, and then
trying to execute that as a function, may
not work.
....But I'm still reading the standard...
Stephen
Nov 14 '05 #18

P: n/a
On Sun, 23 May 2004 16:48:53 +0100, Christian Bau
<ch***********@cbau.freeserve.co.uk> wrote in comp.lang.c:
In article <40***************@cast-com.net>,
"Stephen L." <sd*********@cast-com.net> wrote:
Martin Dickopp wrote:

[ snip ]

Secondly, `sizeof (void *)' (the size of a generic object pointer) need
not be the same as `sizeof (AUX_RGBImageRec *)' (the size of a pointer
to `AUX_RGBImageRec'), so the `memset' call doesn't even get the size
right.
Are you saying that `sizeof (AUX_RGBImageRec *) != sizeof (void *)'?

So, `AUX_RGBImageRec *' could _never_ be used inside the
compare function of `qsort(3C)' since its pointer size may
be different than the size of a `void *'?!!!


When you pass a pointer to qsort, you cast it to void*. Same thing as


When you pass a pointer to qsort(), you cast it to void* if you use a
cast operator to do so. If you have included <stdlib.h> or otherwise
have a correct prototype for qsort() in scope, the first pointer that
you pass to it is converted to "const void *", regardless of any cast
operator you might or might not explicitly code.
when you pass a short to a function that has a long argument.


When you pass a short value to a function whose prototype calls for a
value of type long, there is an implicit conversion of the short value
to a long. There is no cast unless you specifically code a cast.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #19

P: n/a
On Sun, 23 May 2004 19:36:20 -0400, "Stephen L."
<sd*********@cast-com.net> wrote in comp.lang.c:
Kevin Bagust wrote:

In article <40***************@cast-com.net>,
Stephen L. <sd*********@cast-com.net> wrote:
Martin Dickopp wrote:
>

>
> > If anyone believes that pointers to two different
> > types (even if one of the types is the `void' type)
> > are not the _same_ size; could be _different_ size(s)...


From the C99 Standard. Section 6.2.5.26

A pointer to void shall have the same representation and alignment
requirements as a pointer to a character type. Similarly, pointers to
qualified or unqualified versions of compatible types shall have the same
representation and alignment requirements. All pointers to structure
types shall have the same representation and alignment requirements as
each other. All pointers to union types shall have the same
representation and alignment requirements as each other. Pointers to
other types need not to have the same representation and alignment
requirements.

This spells out that pointers to two different types need not be the same
size unless they are specified to be the same representation in the
preceding paragraph from the standard.

Kevin.


Yes, I _just_ found that reading my draft version
of the standard (there's more than just that paragraph).
The text doesn't actually use the word "size",
but you're making that connection and the phrase
"same representation", correct?


[snip]

Representation includes both the amount of memory occupied (i.e.,
size) and the interpretation of the bit pattern.

It is about time you stopped spouting nonsense and started paying
attention. You seem to have some experience with one or a few
compilers on one or a few particular platforms and thing you are
familiar with everything the C language encompasses.

There are platforms where pointers to void and the character types
actually do both occupy more space and contain more significant bits
than pointers to any other data types. This is quite frequently the
case on architectures where the minimum addressable machine word is
very wise, such as 32 or 64 bits.

Such platforms have two choices:

1. Define all of the integer types, even chars, to have 32 or 64 bits
(CHAR_BIT > 8). There are some perfectly conforming C implementations
that do this.

2. Automatically pack and un-pack characters from machine words which
hold multiple characters (rather like packed arrays in Pascal). All
other types occupy one or more full machine words. There are
perfectly conforming C implementations for these architectures as
well. In this case, pointers to char and therefore pointers to void
have more information than other pointer types. They not only must
contain the address of a machine word, as all other pointer types do,
but also some extra bits specifying which 8 bits out of the 32 or 64
are being referenced.

This happens to be true whether you like it or agree with it or not.

As for pointers to function, there is no conversion defined by the C
standard between pointers to any object type (including pointer to
void), and pointer to any kind of function. There is no requirement
or guarantee that there be any meaningful correspondence between them
at all.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #20

P: n/a
>>>In article <40***************@cast-com.net>
"Stephen L." <sd*********@cast-com.net> wrote:
Are you saying that `sizeof (AUX_RGBImageRec *) != sizeof (void *)'?
Chris Torek wrote:
Possibly, yes.

In article <news:40***************@cast-com.net>
Stephen L. <sd*********@cast-com.net> writes:"The same is true in C. While things may be big and small,
pointers come in one size (relatively small).[1]"
http://www.oreilly.com/catalog/pcp3/chapter/ch13.html


This book appears to concern itself mainly with Windows and Unix
systems. C runs on a lot of machines that do not and may never
run either of those OSes, including today's canonical example, the
IBM AS/400. Even in the old K&R-1 or "Classic C" days, however,
the statement was not true: certain Prime (or Pr1me) machines, for
instance, had 48-bit "char *" pointers and 32-bit pointers for
other data types. And of course, as footnote [1] points out, the
claim is not even true on IBM PCs. :-)

(I will note, as an aside, that "near" and "far" break the model
required by Standard C. As long as one uses spellings like "__near"
and "__far", and make it clear that one is writing Zorgonese-C
instead of ANSI-C, this is not an insurmountable problem. You
simply abandon Standard C and charge off into the weeds.)

If you widen the allowable set of Unix-like and even Unix-based
systems, the claim becomes questionable again: for instance, modern
Solaris-on-SPARC systems have both 32- and 64-bit pointers. The
selection is not based on the target type, however, but rather on
compiler flags.

If you write in Standard C, you will not be able to make as many
assumptions about the underlying system -- such as "pointers come
in only one size" -- but your code will work on every Standard C
system. If you find that valuable (and in my experience, it is
usually more valuable than one first suspects), you might as well
work at writing Standard C, rather than Zorgonese.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #21

P: n/a
"Stephen L." <sd*********@cast-com.net> writes:
Kevin Bagust wrote:
> > > If anyone believes that pointers to two different
> > > types (even if one of the types is the `void' type)
> > > are not the _same_ size; could be _different_ size(s)...
From the C99 Standard. Section 6.2.5.26

A pointer to void shall have the same representation and alignment
requirements as a pointer to a character type. Similarly, pointers to
qualified or unqualified versions of compatible types shall have the same
representation and alignment requirements. All pointers to structure
types shall have the same representation and alignment requirements as
each other. All pointers to union types shall have the same
representation and alignment requirements as each other. Pointers to
other types need not to have the same representation and alignment
requirements.

This spells out that pointers to two different types need not be the same
size unless they are specified to be the same representation in the
preceding paragraph from the standard.


Yes, I _just_ found that reading my draft version
of the standard (there's more than just that paragraph).
The text doesn't actually use the word "size",
but you're making that connection and the phrase
"same representation", correct?


6.2.6.1#4 defines what a "representation" is.
I always though of a `void *' as a generic pointer type, however, the
last sentence implies that there are pointers which may not be
contained in a `void *'.
Not sure what you mean by "contained", however I don't think the quoted
text implies anything about that. 6.3.2.3#1 makes it clear that any
pointer to object (or incomplete) type may be converted to `void *' and
vice versa; if an object pointer is converted to `void *' and then back
again to the original type, the result compares equal to the original
pointer. No such guarantee is made for function pointers: they cannot
be converted to `void *'.
Ignoring the alignment requirements parts of the text, a function
pointer comes to mind (on some architectures) that may be represented
differently. But what does that mean? Does it mean its size is
different from that of a `char *',
Allowed, but not required.
or does it mean its value is interpreted _differently_ (maybe the
components of the address it represents are in a different order or
scale then the components for a `char *'). Or does it mean both.
Don't know what you mean by "components of the address"; the standard
doesn't define such a term.

Since you cannot call a function through a pointer to `char' or access
an object through a function pointer, they are certainly interpreted
differently.
I'm not entirely convinced that their intentional use of the phrase
"same representation" includes a pointer's size as well.
Read the definition of "representation" carefully.
A pointer type of a different _size_, well, would be a whole _new_
pointer type, I believe.
Yes, if two pointer types have different size, they are necessarily
pointers to different types.
What I read is that the standard is trying to address a pointer's
access - read/write or execute.
Where does the standard define "a pointer's access"?
A function pointer (having an `execute' attribute)
The standard doesn't use any such term as "execute attribute".
does not have to have the same representation as a `char *' (having
read/write access). The standard doesn't have to differentiate
between the two, either, or warn if a function pointer is dereferenced
as a `char *'.
What do mean by "a function pointer is dereferenced as a `char *'"?

Conversion of a function pointer to `char *' is undefined behavior.
My understanding (aside from all of the alignment language) is that
pointers of the same attribute have compatible access.
What do you mean by "attribute [of a pointer]" or "compatible access"?
The standard doesn't define such terms.
All function pointers (containing a valid function pointer) can be
executed,
A function pointer itself cannot be executed. However, the function
call operator can be applied to it, causing the function designated by
the pointer to be called.
But, if you put a function pointer into a `char *'
.... then you do something which the standard doesn't explicitly define,
thereby causing undefined behavior (see 4#2).
and dereference it, the standard (IMHO) is saying that it doesn't have
to point to the binary value of the start of your function. The
pointer value could be interpreted in a completely different way as an
access pointer.
That could happen (for any definition of "access pointer"), or the
program could print out the complete content of the bible, and then
terminate. IOW, as soon as the behavior is undefined, /anything/ is
allowed to happen as far as the standard is concerned.
Likewise, converting a `char *', pointing to valid machine
instructions, to a function *, and then trying to execute that as a
function, may not work.


Indeed. Converting a pointer to `char' to a function pointer is
undefined behavior.

Martin
--
,--. Martin Dickopp, Dresden, Germany ,= ,-_-. =.
/ ,- ) http://www.zero-based.org/ ((_/)o o(\_))
\ `-' `-'(. .)`-'
`-. Debian, a variant of the GNU operating system. \_/
Nov 14 '05 #22

P: n/a
Martin Dickopp wrote:

"Stephen L." <sd*********@cast-com.net> writes:
Kevin Bagust wrote:

> > > If anyone believes that pointers to two different
> > > types (even if one of the types is the `void' type)
> > > are not the _same_ size; could be _different_ size(s)...

From the C99 Standard. Section 6.2.5.26

A pointer to void shall have the same representation and alignment
requirements as a pointer to a character type. Similarly, pointers to
qualified or unqualified versions of compatible types shall have the same
representation and alignment requirements. All pointers to structure
types shall have the same representation and alignment requirements as
each other. All pointers to union types shall have the same
representation and alignment requirements as each other. Pointers to
other types need not to have the same representation and alignment
requirements.

This spells out that pointers to two different types need not be the same
size unless they are specified to be the same representation in the
preceding paragraph from the standard.


[ snip ]

6.2.6.1#4 defines what a "representation" is.
[ moved to end ]

I always though of a `void *' as a generic pointer type, however, the
last sentence implies that there are pointers which may not be
contained in a `void *'.
Not sure what you mean by "contained", however I don't think the quoted


6.2.6.1#2, ..."contiguous sequences of one or more bytes,"...

A pointer (being an "object" in 6.2.6.1#2) contains, or is made
up of a "contiguous sequences of one or more bytes,". The
exception to 6.2.6.1#2 are bit-fields.

If, as posters are stating, pointers can be different sizes,
then it follows that a pointer may "contain" more bytes than
a `void *' or less bytes then a `void *'. That's what this
thread is about - remember, a poster stated that the size of
a `struct *' does not have to be the same size as a `void *'.
Another posting tried to illustrate this with a 1 MEG `void *'
example. We seem to be drifting from the original discussion.

text implies anything about that. 6.3.2.3#1 makes it clear that any
pointer to object (or incomplete) type may be converted to `void *' and
vice versa; if an object pointer is converted to `void *' and then back
again to the original type, the result compares equal to the original
pointer. No such guarantee is made for function pointers: they cannot
be converted to `void *'.
We were discussing its size, not its ability to be converted.
Ignoring the alignment requirements parts of the text, a function
pointer comes to mind (on some architectures) that may be represented
differently. But what does that mean? Does it mean its size is
different from that of a `char *',
Allowed, but not required.
or does it mean its value is interpreted _differently_ (maybe the
components of the address it represents are in a different order or
scale then the components for a `char *'). Or does it mean both.


Don't know what you mean by "components of the address"; the standard
doesn't define such a term.


But "components of the address" is a fair reading. If something
is made up of a sequence of bytes, then each byte of that sequence
is a _component_ of that something.

6.2.6.1#2, ..."contiguous sequences of one or more bytes,"...
[ snip'd - my O/T theory/discussion about pointer access, etc. ]

A function pointer itself cannot be executed. However, the function
call operator can be applied to it, causing the function designated by
the pointer to be called.
Bad wording on my part, you're wording is more accurate.

---------------

6.2.6.1#4 defines what a "representation" is.


This simply states (in addition to other restrictions and
not forgetting #2) that a `long' {object} type must be represented
by "n×CHAR_BIT bits", and a `double' must be represented by
"n×CHAR_BIT bits", etc., where `n' is the size of the object
for the type. In other words, you can't have a long type
represented as 34-bits on a platform where CHAR_BIT is 8.

But, isn't a pointer a distinct type (like int, char, etc.)
in the standard?

So, a pointer type must be represented by "n×CHAR_BIT bits".

Just as all doubles must be represented by "n×CHAR_BIT bits",
all ints by "n×CHAR_BIT bits", etc., where `n' is the
size of the (type) object. The size of a type is
hard-wired - on a platform where an int is represented
by 4 bytes, its _always_ represented by 4 bytes. Even
if the _value_ of that int can be wholly contained in
7 bits (or whatever). Likewise for a pointer, it size
and representation are the same no matter what type
(it points to) - void, char, int, struct, double, etc.
I am at a complete loss to see a reasonable definition
that allows a `void *' to be a different size than
a `struct *', where the following is TRUE -

sizeof (void *) != sizeof (some_struct *)
I appreciate you time in this discussion, Maritn.
Stephen
Nov 14 '05 #23

P: n/a
"Chris Torek" <no****@torek.net> wrote in message
news:c8*********@news4.newsguy.com...
In article <news:40***************@cast-com.net>
Stephen L. <sd*********@cast-com.net> writes:
"The same is true in C. While things may be big and small,
pointers come in one size (relatively small).[1]"
http://www.oreilly.com/catalog/pcp3/chapter/ch13.html


This book appears to concern itself mainly with Windows and Unix
systems. C runs on a lot of machines that do not and may never
run either of those OSes, including today's canonical example, the
IBM AS/400. Even in the old K&R-1 or "Classic C" days, however,
the statement was not true: certain Prime (or Pr1me) machines, for
instance, had 48-bit "char *" pointers and 32-bit pointers for
other data types. And of course, as footnote [1] points out, the
claim is not even true on IBM PCs. :-)


I'll also note that GCC is adding support for bounded pointers, which
consume 96 bits on a 32-bit platform, etc. Since the change isn't visible
to conforming programs, this doesn't, as far as I can tell, break compliance
with C89/99. Of course, it does break most ABIs, but that's a different
matter...

S

--
Stephen Sprunk "Stupid people surround themselves with smart
CCIE #3723 people. Smart people surround themselves with
K5SSS smart people who disagree with them." --Aaron Sorkin

Nov 14 '05 #24

P: n/a
Stephen L. wrote:
I am at a complete loss to see a reasonable definition
that allows a `void *' to be a different size than
a `struct *', where the following is TRUE -

sizeof (void *) != sizeof (some_struct *)


You should stop writing and start thinking.

There is nothing mutually exclusive about:

1. All object pointers can be converted to a pointer to void
and back again.

2. Different object pointers can have different sizes.
--
Thomas.

Nov 14 '05 #25

P: n/a
Jack Klein wrote:

[snip]

Representation includes both the amount of memory occupied (i.e.,
size) and the interpretation of the bit pattern.

It is about time you stopped spouting nonsense and started paying
attention. You seem to have some experience with one or a few
compilers on one or a few particular platforms and thing you are
familiar with everything the C language encompasses.

2. Automatically pack and un-pack characters from machine words which
hold multiple characters (rather like packed arrays in Pascal).

I think you're (honestly) referring to machines which
don't have byte addressing in their architecture, so
getting at a character that's on an odd address involves
reading the whole word (for argument's sake, 16 bits)
and manipulating it to the "correct" position in the
machine's registers. But the necessity of this operation
can be determined by looking at the LSB(s) of the address.
The pointer itself doesn't need extra "helper/magic" bits.

Some mainframes are like this.
All other types occupy one or more full machine words. There are
perfectly conforming C implementations for these architectures as
well. In this case, pointers to char and therefore pointers to void
have more information than other pointer types. They not only must
contain the address of a machine word, as all other pointer types do,
but also some extra bits specifying which 8 bits out of the 32 or 64
are being referenced.


Let's see...

I hope you agree with the standard that `void *' and
`char *' have the same representation and alignment.

On my Sparc, If I build a 64-bit application, it's possible
that any pointer to char _might_ be "wider" than 64-bits,
based on your argument above.

How much wider? Well, the standard seems to imply it must
be an integral of CHAR_BIT, so the next size (since CHAR_BIT
is 8 on my Sparc) is 72 bits. (But pointers on Sparc must
be aligned to an 8 byte boundary (in 64-bit mode), so it
follows that an array of `char *'s will have a maximum
of 3 bytes of padding between each pointer.)

So my Sparc must read a total of _at least_ 72 bits,
64 for the "actual" pointer to my char, and some other
unspecified amount (at least 3 bits, but may 4 if the
magic is signed) to tell where the `char', that is
pointed to, _actually_ is in memory. Again, this is
what you're saying. Let me illustrate ---
char *foo = malloc(1);
....could _never_ work because I've only allocated a single
byte for the character's position. You've stated that
the character _really_ could be in one of 8 positions
(because I'm running in 64-bit mode), so my `malloc()' is
actually wrong. I've been caught by the infamous
"off by seven" bug which plagues modern software professionals.

So, I must `malloc()' the correct number of bytes
to contain a single char -

char *foo = malloc(8);

It gets better... Consider ->

char str[] = "ab";
char *p1 = &str[ 0 ];
char *p2 = &str[ 1 ];

Not only do `p1' and `p2' differ by the value of
their address (which I have absolutely no problem with),
but the "magic" bits, telling which 8 bits out of the
64 to use to _find_ the char, may be different too.

This because the Sparc, when reading 64 bits at once,
must read them on a 64 bit boundry. Either of `p1'/`p2'
satisfy the requirement, but not both.

Or are you suggesting that it will read 8 consecutive
bytes beginning at the address, decode the magic bits,
then figure out what byte is the _real_ char?

If I increment `p1' so that its value matches that of
`p2', does its value remain unchanged, but the magic
bit(s) change to reflect the new _relative_ postition of
the character in the "machine word"?

---

Stephen
Nov 14 '05 #26

P: n/a
In <ch*********************************@slb-newsm1.svr.pol.co.uk> Christian Bau <ch***********@cbau.freeserve.co.uk> writes:
When you pass a pointer to qsort, you cast it to void*. Same thing as
when you pass a short to a function that has a long argument.


If adequate declarations are in scope for these functions, you don't cast
*anything*: the compiler will perform implicitly the necessary
conversions.

A cast is a syntactic construct (an operator) requiring an *explicit*
conversion to be performed. Implicit conversions have *nothing*
to do with the cast *operator*.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 14 '05 #27

P: n/a
Chris Torek wrote:
In article <40***************@cast-com.net>
"Stephen L." <sd*********@cast-com.net> wrote:
> Are you saying that `sizeof (AUX_RGBImageRec *) != sizeof (void *)'?
Chris Torek wrote:
Possibly, yes.


In article <news:40***************@cast-com.net>
Stephen L. <sd*********@cast-com.net> writes:
"The same is true in C. While things may be big and small,
pointers come in one size (relatively small).[1]"
http://www.oreilly.com/catalog/pcp3/chapter/ch13.html


This book appears to concern itself mainly with Windows and Unix
systems.


My initial fustration was that it appeared some posters
were confusing the object pointed to with the pointer itself.
The book link offered an explaination of the difference.
C runs on a lot of machines that do not and may never
run either of those OSes, including today's canonical example, the
IBM AS/400. Even in the old K&R-1 or "Classic C" days, however,
the statement was not true: certain Prime (or Pr1me) machines, for
instance, had 48-bit "char *" pointers and 32-bit pointers for
other data types. And of course, as footnote [1] points out, the
claim is not even true on IBM PCs. :-)
I see. What it really comes down to is that C pointers
are/have evolved. The pointers `void *' and `char *'
should be thought as unique and new C types having very
special qualities beyond pointer to type.

I can digest that, thanks.
How does that something like -

typedef struct {
char ch;
} ch_t;

ch_t *a_ch;

On an architecture with 48-bit "char *" pointers
and 32-bit pointers for other data types, what would

sizeof (a_ch)
sizeof (int *)

be (I'm not trying to be funny)?

If you write in Standard C, you will not be able to make as many
assumptions about the underlying system -- such as "pointers come
in only one size" -- but your code will work on every Standard C
system. If you find that valuable (and in my experience, it is
usually more valuable than one first suspects), you might as well
work at writing Standard C, rather than Zorgonese.

Thanks,

Stephen
Nov 14 '05 #28

P: n/a

On Mon, 24 May 2004, Stephen L. wrote:

Jack Klein wrote:

It is about time you stopped spouting nonsense and started paying
attention. [...] <snip> 2. Automatically pack and un-pack characters from machine words which
hold multiple characters (rather like packed arrays in Pascal).
I think you're (honestly) referring to machines which
don't have byte addressing in their architecture,


Of course he's not. He's talking about machines which *do* have
word addressing, but whose words are "too long" to space-efficiently
equate 'char' with a machine word. For example, consider a machine
with 16-bit machine words. (The concept of "byte" is irrelevant to
this architecture; it has no "bytes" to speak of.)
On this machine, memory is organized into 16-bit words. However,
to use a single machine word for each 'char' (which let's suppose
are encoded in 7-bit ASCII plus one bit for conformance) would be
wasteful. So we stick two 'char's in each machine word; that is,
where a pointer to 'int' would be 16 bits wide and contain

+-----------------+[0]
| machine address | pointer to 'int' (16 bits)
+-----------------+

a pointer to 'char' must be at least 17 bits wide and contain

+-----------------+--------+
| machine address | offset | pointer to 'char' (17+ bits)
+-----------------+--------+

Now the deductive stages necessary to show conformance to the
requirements of the C standard.
Since CHAR_BIT is 8, the width of a char pointer must be (the
least-wasteful) multiple of 8 greater than or equal to 17; namely,
24 bits, or 3 bytes. (This is using the C Standard's definition
of "byte"; now that we know how wide a 'char' is, the word "byte"
makes sense. Before we had defined 'char', of course, the word
"byte" couldn't be defined.)

Furthermore, note that while a 'pointer to pointer to int'
can have 16 bits (since pointers to int are aligned on word boundaries),
a 'pointer to pointer to char' must have at least 24 bits (since
it must be able to point to a 24-bit 'pointer to char').
(We could of course fix this by letting sizeof(char*)==32 instead
of 24, but again that could turn out to be very wasteful in string-
heavy C programs. It would probably pay to let sizeof(char**)==32,
though, since pointers to pointers are sufficiently rare. This is
a design decision, and might reasonably be affected by compiler
switches.)
so
getting at a character that's on an odd address involves
reading the whole word (for argument's sake, 16 bits)
and manipulating it to the "correct" position in the
machine's registers. But the necessity of this operation
can be determined by looking at the LSB(s) of the address.
The pointer itself doesn't need extra "helper/magic" bits.
You now see why that is an incorrect statement.

All other types occupy one or more full machine words. There are
perfectly conforming C implementations for these architectures as
well. In this case, pointers to char and therefore pointers to void
have more information than other pointer types. They not only must
contain the address of a machine word, as all other pointer types do,
but also some extra bits specifying which 8 bits out of the 32 or 64
are being referenced.


Let's see...

I hope you agree with the standard that `void *' and
`char *' have the same representation and alignment.


Naturally (for some values of "char *" --- Google for long
pedantic discussions on the meaning of "a character type").
On my Sparc, If I build a 64-bit application, it's possible
that any pointer to char _might_ be "wider" than 64-bits,
based on your argument above.
Naturally. I don't know Sparc, but I would guess that in practice,
it neither will have access to 2**64 words of memory, nor will it
really lack 8-bit instructions. For the sake of argument, we'll
assume both of the above.
How much wider? Well, the standard seems to imply it must
be an integral of CHAR_BIT, so the next size (since CHAR_BIT
is 8 on my Sparc) is 72 bits. (But pointers on Sparc must
be aligned to an 8 byte boundary (in 64-bit mode), so it
follows that an array of `char *'s will have a maximum
of 3 bytes of padding between each pointer.)
s/maximum/minimum/. Yes.
So my Sparc must read a total of _at least_ 72 bits,
64 for the "actual" pointer to my char, and some other
unspecified amount (at least 3 bits, but may 4 if the
magic is signed)
Not that that makes any sense. Engage your brain, please!
to tell where the `char', that is
pointed to, _actually_ is in memory. Again, this is
what you're saying. Let me illustrate ---

char *foo = malloc(1);

...could _never_ work because I've only allocated a single
byte for the character's position.
You're saying that you wrote a buggy 'malloc' library for your
Sparc? Then you'd better fix it posthaste! One of the obvious
ramifications of word-addressed architecture is that 'malloc' must
be able to handle requests for odd numbers of bytes. (On the
average system, of course, this request will really allocate between
2 and 32 bytes of storage, for the convenience of the inevitable
'realloc'.)
You've stated that
the character _really_ could be in one of 8 positions
(because I'm running in 64-bit mode), so my `malloc()' is
actually wrong. I've been caught by the infamous
"off by seven" bug which plagues modern software professionals.
Modern software professionals don't write buggy memory managers.[1]

<snip nonsense>
char str[] = "ab";
char *p1 = &str[ 0 ];
char *p2 = &str[ 1 ];

Not only do `p1' and `p2' differ by the value of
their address (which I have absolutely no problem with),
but the "magic" bits, telling which 8 bits out of the
64 to use to _find_ the char, may be different too.
Obviously. They point different places; their values must
necessarily be different. If they had the same values, they'd
be pointing to the same place. Isn't this obvious?
If I increment `p1' so that its value matches that of
`p2', does its value remain unchanged, but the magic
bit(s) change to reflect the new _relative_ postition of
the character in the "machine word"?


Obviously. When I write
int i=1;
and then
i=2;
doesn't the value of 'i' change to reflect the new integer
value of 'i'? Why should pointers be any different?[2]

-Arthur

[0] - Here, one "box" represents one machine word. This is
not the same thing as one "byte"; we haven't defined what a
"byte" is for this C implementation yet. (But we will.)
[1] - Yes, they do. But not so blatantly wrong as all that.
[2] - That was a rhetorical question. Please don't respond
stupidly _just_ yet; think it over.
Nov 14 '05 #29

P: n/a

On Mon, 24 May 2004, Stephen L. wrote:

typedef struct {
char ch;
} ch_t;

ch_t *a_ch;

On an architecture with 48-bit "char *" pointers
and 32-bit pointers for other data types, what would

sizeof (a_ch)
sizeof (int *)

be (I'm not trying to be funny)?


Obviously, since 'a_ch' is not a "char *" pointer, its
size is 32 bits. Ditto 'int *': 32 bits.

Here's a followup exercise: Flurgs are green and everything
else is blue. What color are zoids and blurbs, given that neither
of them are flurgs?

-Arthur
Nov 14 '05 #30

P: n/a
In <40***************@cast-com.net> "Stephen L." <sd*********@cast-com.net> writes:
A pointer (being an "object" in 6.2.6.1#2) contains, or is made
up of a "contiguous sequences of one or more bytes,". The
exception to 6.2.6.1#2 are bit-fields.

If, as posters are stating, pointers can be different sizes,
then it follows that a pointer may "contain" more bytes than
a `void *' or less bytes then a `void *'. That's what this
thread is about - remember, a poster stated that the size of
a `struct *' does not have to be the same size as a `void *'.
Another posting tried to illustrate this with a 1 MEG `void *'
example. We seem to be drifting from the original discussion.
text implies anything about that. 6.3.2.3#1 makes it clear that any
pointer to object (or incomplete) type may be converted to `void *' and
vice versa; if an object pointer is converted to `void *' and then back
again to the original type, the result compares equal to the original
pointer. No such guarantee is made for function pointers: they cannot
be converted to `void *'.


We were discussing its size, not its ability to be converted.


Now, try to engage your brain. Imagine that a certain object pointer type
contained more *information* than a void pointer type. Would it be
possible to convert *any* pointer value of that type to void pointer and
back without loss of information?

So, the only way one can imagine pointer types with a size greater than
that of void pointers is by introducing padding bytes, that don't
contribute to the actual pointer value. While this is perfectly possible
in theory, it's not going to happen in practice.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Nov 14 '05 #31

P: n/a
In article <40***************@cast-com.net>
Stephen L. <sd*********@cast-com.net> writes:
I see. What it really comes down to is that C pointers
are/have evolved. The pointers `void *' and `char *'
should be thought as unique and new C types having very
special qualities beyond pointer to type.
Actually, it is more that "char" itself is special, and as a result,
so is "char *". That "specialness" need not propagate any further,
but of course "void *" and "char *" are really "the same thing"
underneath -- in particular, they have the same representation.

I saved this:

In article <news:d7**************************@posting.google. com>
Holger Hasselbach <ha********@galad.com> writes:As far as I understand it now, thanks to the excellent explanations
from Chris, the C system of object storage can be expressed in three
layers.

Layer 3: Interpretation - Used values
Layer 2: Representation - Pure binary, unsigned char
Layer 1: Storage - Hardware
The "hardware" layer (Layer 1) is simply dictated by the hardware.
Someone built a machine, and it does whatever it does. The "Layer
2" part is part of Standard C, and imposes special features on
(unsigned) char, and therefore pointers-to-unsigned-char: these
things get at a "pure binary" set of bits that are used to represent
every object in C. More precisely, they represent addressable
objects -- ones where &x works -- as thing stored in registers can
"cheat".

The topmost Layer 3 items normally go right back to whatever the
hardware provides: if an "int" uses 42 bits scattered across 8
9-bit "C bytes", and ignores the remaining 30 bits entirely or uses
them as a checksum of the other 42 or whatever, this is not a
problem. Here sizeof(int) is 8 and CHAR_BIT is 9, and 8 x 9 = 72,
and using "unsigned char *" you can access all 72 bits, but regular
old "int" only uses 42 of them to determine the int's value.

So now, proceeding on to one of these word-addressed machines:
typedef struct {
char ch;
} ch_t;

ch_t *a_ch;

On an architecture with 48-bit "char *" pointers
and 32-bit pointers for other data types, what would

sizeof (a_ch)
sizeof (int *)

be (I'm not trying to be funny)?


Here the fundamental "word size" of the machine is 16 bits, and
regular "machine level" pointers -- "int *" for instance -- use
two machine-words to point to a third machine word. (I am assuming
16-bit "int"s here, and that a 32-bit long is an integral type that
happens to be the right size to hold a machine-level pointer, on
this machine.)

The machine's word size is 16 bits, but the implementor chose to
provide 8-bit "unsigned char"s. Hence, a "char *" requires a pair
of entities: <32-bit machine-level pointer, 16-bit auxiliary word
to select even/odd byte>.

The unnamed struct above has an 8-bit "char" and 8 bits of padding,
so that sizeof(struct unnamed) -- which is of course the same as
sizeof(ch_t) -- is 2.

Since a "ch_t" always occupies an entire machine word, only one
32-bit machine-level pointer is required to address it. This
means that "sizeof(a_ch) -- or sizeof(struct unnamed *) -- is
4 (because CHAR_BIT is 8 and machine-level pointers use 2 16-bit
machine-level words). Likewise, an "int" always occupies a complete
16-bit machine-level word, and "sizeof(int *)" is also 4. But
sizeof(char *), sizeof(unsigned char *), and sizeof(void *) are
all 6 -- they use two machine-level words to hold a machine-level
pointer, plus a third machine-level word to hold a single bit
to select "even/odd byte within word".

Note that the malloc() function must locate a contiguous chunk of
16-bit machine-level words, giving a 32-bit value that points to
whole words. It must then convert its return value from "machine-level
pointer" to "C-level byte-pointer", by tacking on a third 16-bit
word saying "use the first C-byte of this word". Conversions
from "char *" to "T *", for "normal" machine-level types and for
structure types, simply discard the byte-offset value, and
conversions from "T *" to "char *" always add a zero byte-offset.
(And, of course, "void *" and "char *" are really "the same"
underneath, so T here never stands for "void".)

These kinds of machines are rare (perhaps even nonexistent) today.
They were pretty much wiped out by the 8-bit-byte "killer
microprocessors", which ate the traditional "minicomputer" market
entirely, and have taken a bite out of of the traditional mainframe
markets. The IBM AS/400 architecture still preserves some of this
sort of ornamentation, but the AS/400 is, as far as I know, a
byte-addressed (virtual) machine.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #32

P: n/a
"Stephen L." <sd*********@cast-com.net> writes:
Martin Dickopp wrote:

6.2.6.1#4 defines what a "representation" is.
This simply states (in addition to other restrictions and
not forgetting #2) that a `long' {object} type must be represented
by "n×CHAR_BIT bits", and a `double' must be represented by
"n×CHAR_BIT bits", etc., where `n' is the size of the object
for the type. In other words, you can't have a long type
represented as 34-bits on a platform where CHAR_BIT is 8.


No, it states:

| Values stored in non-bit-field objects of any other object type
| consist of n × CHAR_BIT bits, where n is the size of an object of that
| type, in bytes. The value may be copied into an object of type
| unsigned char [n] (e.g., by memcpy); the resulting set of bytes is
| called the object representation of the value.

So while it is true that the representation of every type must have a
integer multiple of CHAR_BIT bits, that is not the definition of
"representation". The "repesentation" is defined as the set of bytes
that results from copying the value into an array of `unsigned char'.
So, a pointer type must be represented by "n×CHAR_BIT bits".

Just as all doubles must be represented by "n×CHAR_BIT bits",
all ints by "n×CHAR_BIT bits", etc., where `n' is the
size of the (type) object. The size of a type is
hard-wired - on a platform where an int is represented
by 4 bytes, its _always_ represented by 4 bytes. Even
if the _value_ of that int can be wholly contained in
7 bits (or whatever). Likewise for a pointer, it size
and representation are the same no matter what type
(it points to) - void, char, int, struct, double, etc.
6.2.6.1#1: "The representations of all types are unspecified except as
stated in this subclause."

Now it's your turn to quote a verse from "this subclause" (i.e. 6.2.6)
that states that two different pointer types have to have the same
representation. :)

While it is true (on a given implementation) that a pointer to `void'
must have the same size as every other pointer to `void', and a pointer
to `struct foo' must have the same size as every other pointer to
`struct foo', it isn't true a pointer to `void' must have the same size
as a pointer to `struct foo'. Just like just because the sizes of `int'
and `double' are fixed on a given implementation, it doesn't follow that
they must be the same.
I am at a complete loss to see a reasonable definition
that allows a `void *' to be a different size than
a `struct *', where the following is TRUE -

sizeof (void *) != sizeof (some_struct *)


Name the verse in the standard which forbits it, please.

Martin
--
,--. Martin Dickopp, Dresden, Germany ,= ,-_-. =.
/ ,- ) http://www.zero-based.org/ ((_/)o o(\_))
\ `-' `-'(. .)`-'
`-. Debian, a variant of the GNU operating system. \_/
Nov 14 '05 #33

P: n/a
"Arthur J. O'Dwyer" <aj*@nospam.andrew.cmu.edu> wrote:
Of course he's not. He's talking about machines which *do* have
word addressing, but whose words are "too long" to space-efficiently
equate 'char' with a machine word. For example, consider a machine
with 16-bit machine words. (The concept of "byte" is irrelevant to
this architecture; it has no "bytes" to speak of.)
On this machine, memory is organized into 16-bit words. However,
to use a single machine word for each 'char' (which let's suppose
are encoded in 7-bit ASCII plus one bit for conformance) would be
wasteful. So we stick two 'char's in each machine word; that is,
where a pointer to 'int' would be 16 bits wide and contain

+-----------------+[0]
| machine address | pointer to 'int' (16 bits)
+-----------------+

a pointer to 'char' must be at least 17 bits wide and contain

+-----------------+--------+
| machine address | offset | pointer to 'char' (17+ bits)
+-----------------+--------+

Now the deductive stages necessary to show conformance to the
requirements of the C standard.
Since CHAR_BIT is 8, the width of a char pointer must be (the
least-wasteful) multiple of 8 greater than or equal to 17; namely,
24 bits, or 3 bytes. (This is using the C Standard's definition
of "byte"; now that we know how wide a 'char' is, the word "byte"
makes sense. Before we had defined 'char', of course, the word
"byte" couldn't be defined.)
If you make the size of (char *) be 3 bytes, you will have a terrible time
storing an array of pointer to char:

+---------------------------+---------------------------+
| machine addr 1 offset 1 | machine addr 2 offset 2 | logical layout
+---------------------------+---------------------------+
+----------------+--------------------+-----------------+
| machine addr 1 | offset 1 machine | addr 2 offset 2 | word layout
+----------------+--------------------+-----------------+

Notice the split of the second machine address between two different words.
Now it's not just chars that have to be packed and unpacked all the time,
but pointers to char or void also require careful packing and unpacking.
Furthermore, note that while a 'pointer to pointer to int'
can have 16 bits (since pointers to int are aligned on word boundaries),
a 'pointer to pointer to char' must have at least 24 bits (since
it must be able to point to a 24-bit 'pointer to char').
That'd be the simplest way to address a particular char pointer when they
are packed into machine words.

Or perhaps you could only store the machine address part of a pointer to
pointer to char, and rely on the alignment to work out whether you want to
start from the beginning or the middle of the word when you dereference it.

ie. for big-endian packing of bytes in 16-bit machine words, where int is
16-bit.
pseudocode char *dereference(char **p)
{
char *result;
if(*(unsigned int *)&p % 3) /* If p is an odd machine word */
{
/* First grab machine address from LSB of p[0] and MSB of p[1] */
((unsigned int *)&result)[0] = (*(unsigned int *)p & 0xFF) <<
8
| (*(unsigned int *)(p + 1) & 0xFF00) >>
8;
/* Then grab offset from LSB of p[1] */
((unsigned int *)&result)[1] = (*(unsigned int *)(p + 1) & 0xFF) <<
8;
}
else /* p is an even machine word */
{
result = (char *)p;
}
return result;
}

This requires that the beginning of an array of (char *) be aligned to three
machine words.
(We could of course fix this by letting sizeof(char*)==32 instead
of 24, but again that could turn out to be very wasteful in string-
heavy C programs. It would probably pay to let sizeof(char**)==32,
though, since pointers to pointers are sufficiently rare. This is
a design decision, and might reasonably be affected by compiler
switches.)


ITYM sizeof (char*) == 4, not 32.

--
Simon.
Nov 14 '05 #34

P: n/a
Chris Torek wrote:

In article <40***************@cast-com.net>
Stephen L. <sd*********@cast-com.net> writes:
I see. What it really comes down to is that C pointers
are/have evolved. The pointers `void *' and `char *'
should be thought as unique and new C types having very
special qualities beyond pointer to type.


Actually, it is more that "char" itself is special, and as a result,
so is "char *". That "specialness" need not propagate any further,
but of course "void *" and "char *" are really "the same thing"
underneath -- in particular, they have the same representation.


Now I understand. I really appreciate the
write-up you provided.

Thanks to everyone's patience in explaining that
`char *' and `void *' on some architectures,
can be a different size then pointers to other types.

[ snip ]
Thank you very much.

Stephen
Nov 14 '05 #35

P: n/a
Martin Dickopp wrote:
I am at a complete loss to see a reasonable definition
that allows a `void *' to be a different size than
a `struct *', where the following is TRUE -

sizeof (void *) != sizeof (some_struct *)


Name the verse in the standard which forbits it, please.


No, it's not forbidden, I agree. I was wrong.
I understand _now_ that `char *' and `void *'
are pointer types which, on some architectures,
may contain additional information on how that
pointer is "decoded" for its type (specifically,
for the `char' type).

Thanks to all those who replied to these posts.

Stephen
Nov 14 '05 #36

This discussion thread is closed

Replies have been disabled for this discussion.