Minimum size of void *

R

Rob Hoelz

Hello everyone,

I'm working on a hashtable-based dictionary implementation in C, and it
uses void pointers for data storage, naturally. However, since one of
the data types I will be using it for is unsigned long -> unsigned
long, I figure it'd be a better idea to just cast the unsigned longs
I'm inserted into the void pointer slots to avoid mallocs, frees, and
unnecessary deferencing. On my machine, this is fine; void * are 32
bits. Is this necessarily the case on all machines as per the C
standard? I poured over the C89 specs and couldn't find anything on
pointer size; I assume that it's always native word size, which would
require me to think up a different solution.

Thanks,
Rob Hoelz
 
R

Richard Tobin

I'm working on a hashtable-based dictionary implementation in C, and it
uses void pointers for data storage, naturally. However, since one of
the data types I will be using it for is unsigned long -> unsigned
long, I figure it'd be a better idea to just cast the unsigned longs
I'm inserted into the void pointer slots to avoid mallocs, frees, and
unnecessary deferencing.

Can't you use a union of void * and unsigned long? It may make the
interface a bit messier of course.

-- Richard
 
R

Richard Heathfield

Rob Hoelz said:

On my machine, this is fine; void * are 32
bits. Is this necessarily the case on all machines as per the C
standard?

Nope (and it's not just a Standard thing - real systems exist where a
void * is narrower than 32 bits, and I would be very surprised if there
were not systems with void * being wider than 32 bits, too.

You can, however, guarantee that you can fit the object representation
of a void * into an array of unsigned char having sizeof(void *)
elements. This may be adequate for your purposes.
 
W

Willem

Rob wrote:
) I'm working on a hashtable-based dictionary implementation in C, and it
) uses void pointers for data storage, naturally. However, since one of
) the data types I will be using it for is unsigned long -> unsigned
) long, I figure it'd be a better idea to just cast the unsigned longs
) I'm inserted into the void pointer slots to avoid mallocs, frees, and
) unnecessary deferencing. On my machine, this is fine; void * are 32
) bits. Is this necessarily the case on all machines as per the C
) standard? I poured over the C89 specs and couldn't find anything on
) pointer size; I assume that it's always native word size, which would
) require me to think up a different solution.

Can't you use a union of long and void * ?

SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
R

Richard Heathfield

Willem said:
Rob wrote:
) I'm working on a hashtable-based dictionary implementation in C, and
it
) uses void pointers for data storage, naturally. However, since one
of ) the data types I will be using it for is unsigned long ->
unsigned ) long, I figure it'd be a better idea to just cast the
unsigned longs ) I'm inserted into the void pointer slots to avoid
mallocs, frees, and
) unnecessary deferencing. On my machine, this is fine; void * are
32
) bits. Is this necessarily the case on all machines as per the C
) standard? I poured over the C89 specs and couldn't find anything on
) pointer size; I assume that it's always native word size, which
would ) require me to think up a different solution.

Can't you use a union of long and void * ?

Not without facing up to the possibility that information will be lost
in one direction or the other - this *will* happen if the two types are
not identical in size. If that doesn't matter to him, fine, but I
suspect that it does. (Naturally, my suspicion could be wrong.)
 
R

Rob Hoelz

Richard Heathfield said:
Willem said:


Not without facing up to the possibility that information will be
lost in one direction or the other - this *will* happen if the two
types are not identical in size. If that doesn't matter to him, fine,
but I suspect that it does. (Naturally, my suspicion could be wrong.)

I used a union at first...but then I figured I'd hate to have to say
result.ulong_value everytime I wanted the long...What I really wanted
was union functionality without the union. So I hacked together some
defines in my autoconf script and ended up using this:

#if PTR_GT
typedef keyval_type void *;
#elif PTR_EQ
typedef keyval_type void *;
#elif PTR_LT
typdef keyval_type unsigned long;
#else
#error "You need to tell me how big ulongs and void *s are!"
#endif
 
R

Richard Tobin

Rob Hoelz said:
I used a union at first...but then I figured I'd hate to have to say
result.ulong_value everytime I wanted the long

Annoying, isn't it. It would be nice if the common extension of anonymous
unions within structures was adopted into standard C.

Historically, it's been common to use #defines for this:

#define ulongv result.ulong_value

but it can result in hard-to-find bugs because of namespace pollution.

-- Richard
 
B

Ben Pfaff

Rob Hoelz said:
#if PTR_GT
typedef keyval_type void *;
#elif PTR_EQ
typedef keyval_type void *;
#elif PTR_LT
typdef keyval_type unsigned long;
#else
#error "You need to tell me how big ulongs and void *s are!"
#endif

On a system with new-enough headers, you can #include <stdint.h>,
then use intptr_t or uintptr_t (assuming an appropriate type
exists).
 
W

Walter Roberson

Rob Hoelz said:
Nope (and it's not just a Standard thing - real systems exist where a
void * is narrower than 32 bits, and I would be very surprised if there
were not systems with void * being wider than 32 bits, too.

As any pointer type can be converted to void * and back to the
same pointer type and have the results compare equal to the
original, it follows that void * must be big enough to hold the
largest pointer. On "64 bit machines" (an ill-defined term),
the maximum pointer size might often be 64 bits (even if only,
say, 40 bits of the 64 are used in the hardware of that generation.)

Pointers are not necessarily the same size as is needed for the
maximum size that a particular pointer can spam; e.g., a pointer
that could address a complete 32 bit object might require more than
32 bits to hold, because a "pointer" might include information such
as a segment number -- segmented architectures can allow access
to more memory than can be accessed as a chunk. (It happened historically.
near and far and huge pointers anyhow?) Also, there are some systems
(e.g., Cray) in which a pointer to a character has to include information
about which byte within a hardware word was being accessed, information
not necessarily needed for pointers to the other basic types.
 
K

Keith Thompson

As any pointer type can be converted to void * and back to the
same pointer type and have the results compare equal to the
original, it follows that void * must be big enough to hold the
largest pointer.
[...]

Quibble: function pointers are not convertible to void* and may be
bigger than void*. (Allowing conversion between function pointers and
object pointers is a common extension.)
 
J

jacob navia

Keith said:
As any pointer type can be converted to void * and back to the
same pointer type and have the results compare equal to the
original, it follows that void * must be big enough to hold the
largest pointer.
[...]

Quibble: function pointers are not convertible to void* and may be
bigger than void*. (Allowing conversion between function pointers and
object pointers is a common extension.)

Under AIX function pointers need TWICE as much space as
normal pointers.
 
F

Flash Gordon

jacob navia wrote, On 05/09/07 19:39:
Keith said:
As any pointer type can be converted to void * and back to the
same pointer type and have the results compare equal to the
original, it follows that void * must be big enough to hold the
largest pointer.
[...]

Quibble: function pointers are not convertible to void* and may be
bigger than void*. (Allowing conversion between function pointers and
object pointers is a common extension.)

Under AIX function pointers need TWICE as much space as
normal pointers.

I don't know where you got that impression.
markg@hal02 ~ $ gcc t.c -ansi -pedantic -Wall -W
markg@hal02 ~ $ ./a.out
4 4
markg@hal02 ~ $ cat t.c
#include <stdio.h>

typedef int f(void);

int main(void)
{
fprintf(stdout,"%d %d\n",(int)sizeof(void*),(int)sizeof(f*));
return 0;
}

markg@hal02 ~ $ uname -a
AIX hal02 3 5 0046B53C4C00 unknown unknown AIX
markg@hal02 ~ $

It would have been a valid and appropriate response IF you
were correct. However, you obviously do not know AIX or Unix as wel as
you think.
 
W

Walter Roberson

Flash Gordon said:
#include <stdio.h>
typedef int f(void);
int main(void)
{
fprintf(stdout,"%d %d\n",(int)sizeof(void*),(int)sizeof(f*));
return 0;
}

Tsk, sizeof() returns size_t, which cannot necessarily be
converted losslessly (or with any particular result) to int.
Your program doesn't prove what you set out to establish,
as sizeof(f*) might be greater than INT_MAX :)


If you were using C90, a closer approach would be

fprintf(stdout,"%uld %uld\n",(unsigned long)sizeof(void*),(unsigned long)sizeof(f*));

If you were using C99, I understand there is a direct format code
for size_t.
 
F

Flash Gordon

Walter Roberson wrote, On 05/09/07 20:15:
Tsk, sizeof() returns size_t, which cannot necessarily be
converted losslessly (or with any particular result) to int.
Your program doesn't prove what you set out to establish,
as sizeof(f*) might be greater than INT_MAX :)

markg@hal02 ~ $ gcc t.c -ansi -pedantic -Wall -W
markg@hal02 ~ $ ./a.out
same
markg@hal02 ~ $ cat t.c
#include <stdio.h>

typedef int f(void);

int main(void)
{
puts((sizeof(void*)==sizeof(f*))?"same":"different");
return 0;
}

markg@hal02 ~ $ uname -a
AIX hal02 3 5 0046B53C4C00 unknown unknown AIX
markg@hal02 ~ $

Happy? :)
 
J

jacob navia

Flash said:
Walter Roberson wrote, On 05/09/07 20:15:

markg@hal02 ~ $ gcc t.c -ansi -pedantic -Wall -W
markg@hal02 ~ $ ./a.out
same
markg@hal02 ~ $ cat t.c
#include <stdio.h>

typedef int f(void);

int main(void)
{
puts((sizeof(void*)==sizeof(f*))?"same":"different");
return 0;
}

markg@hal02 ~ $ uname -a
AIX hal02 3 5 0046B53C4C00 unknown unknown AIX
markg@hal02 ~ $

Happy? :)

Under AIX a function pointer is two pointers:
1) The pointer to the code
2) The pointer to the global section of the function, i.e. the
value that will be loaded in a dedicated register for accessing
the global variables.

When you take the address of a function, the compiler generates a
structure with those two pointers, and gives you a pointer to THAT
structure, specially if you write
sizeof(f*)
instead of sizeof(f);
 
F

Flash Gordon

jacob navia wrote, On 05/09/07 20:33:
Under AIX a function pointer is two pointers:
1) The pointer to the code
2) The pointer to the global section of the function, i.e. the
value that will be loaded in a dedicated register for accessing
the global variables.

When you take the address of a function, the compiler generates a
structure with those two pointers, and gives you a pointer to THAT
structure,

So you admit that the pointers as far as C is concerned are the same
size? Keith was talking about whether they could be converted, the
conversion being a common extension and gave size as one possible reason
why it might not be possible. So your reply was at the very least highly
misleading and not relevant to the discussion.
specially if you write
sizeof(f*)
instead of sizeof(f);

The main difference between sizeof(f*) and sizeof(f) is that the first
is legal C the second is not, although gcc allows it as an extension
giving a value of 1. If you can't get that right then why should I
believe what you are claiming about AIX?
 
K

Keith Thompson

jacob navia said:
Under AIX a function pointer is two pointers:
1) The pointer to the code
2) The pointer to the global section of the function, i.e. the
value that will be loaded in a dedicated register for accessing
the global variables.

When you take the address of a function, the compiler generates a
structure with those two pointers, and gives you a pointer to THAT
structure, specially if you write
sizeof(f*)
instead of sizeof(f);

You are mistaken.

If you take the address of a function, what you get is by definition a
function pointer. How it's implemented internally is irrelevant.

Under AIX, as far as a C program is concerned, a function pointer is
the same size as an object pointer. It *could* have been done
differently (for example, the compiler could have treated the pair of
pointers you refer to as a single function pointer).

#include <stdio.h>
int main(void)
{
void (*obj)(void);

printf("sizeof(void*) = %d\n", (int)sizeof(void*));
printf("sizeof(void(*)(void)) = %d\n", (int)sizeof(void(*)(void)));
printf("sizeof obj = %d\n", (int)sizeof obj);
return 0;
}

Under AIX, this program prints all three sizes as 4, or prints all
three sizes as 8, depending on compiler options.

What do you mean by 'sizeof(f*)' and 'sizeof(f)'? What is 'f'?
 
K

Keith Thompson

Keith Thompson said:
jacob navia said:
Under AIX a function pointer is two pointers:
1) The pointer to the code
2) The pointer to the global section of the function, i.e. the
value that will be loaded in a dedicated register for accessing
the global variables.

When you take the address of a function, the compiler generates a
structure with those two pointers, and gives you a pointer to THAT
structure, specially if you write
sizeof(f*)
instead of sizeof(f);

You are mistaken. [snip]
What do you mean by 'sizeof(f*)' and 'sizeof(f)'? What is 'f'?

Sorry, I missed the declaration of f in the previous article:

typedef int f(void);

sizeof(f*) is, of course, a constraint violation.
 
F

Flash Gordon

Keith Thompson wrote, On 05/09/07 21:33:
Keith Thompson said:
jacob navia said:
Under AIX a function pointer is two pointers:
1) The pointer to the code
2) The pointer to the global section of the function, i.e. the
value that will be loaded in a dedicated register for accessing
the global variables.

When you take the address of a function, the compiler generates a
structure with those two pointers, and gives you a pointer to THAT
structure, specially if you write
sizeof(f*)
instead of sizeof(f);
You are mistaken. [snip]
What do you mean by 'sizeof(f*)' and 'sizeof(f)'? What is 'f'?

Sorry, I missed the declaration of f in the previous article:

typedef int f(void);

sizeof(f*) is, of course, a constraint violation.

Surely you mean sizeof(f) is a constraint violation because it is taking
the size of a function type, whereas sizeof(f*) is legal because i is
taking the size of a pointer to a function.
 
B

Ben Pfaff

Keith Thompson said:
typedef int f(void);

sizeof(f*) is, of course, a constraint violation.

Taking the size of a pointer-to-function, via sizeof(f*), is not
a constraint violation.

Attempting to take the size of a function, via sizeof(f), would
be a constraint violation.
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top