void*

Not exactly...it's "undefined". Some compilers, like gcc, accept it.
Others don't. That code is intended to improve virtual memory
performance; such code is, unfortunately, system-dependent and belongs
in the non-existant bottle we need to keep system-dependent stuff.

Randolph

···

On Sun, Oct 03, 2004 at 04:16:40PM -0700, Randolph Fritz wrote:

>
> But you're right. Even if most compilers allow it, by the books
> it's not legal to do pointer arithmetic with void pointers.
> The solution is probably to just change it back:
>

> >
> > But you're right. Even if most compilers allow it, by the books
> > it's not legal to do pointer arithmetic with void pointers.
> > The solution is probably to just change it back:
> >

Not exactly...it's "undefined". Some compilers, like gcc, accept it.

gcc in C mode accepts it, but not when using C++.

[erwin@drake erwin]$ gcc -c void.c
[erwin@drake erwin]$ g++ -c void.c
void.c: In function `int main()':
void.c:3: error: ISO C++ forbids incrementing a pointer of type `void*'

···

On Sun, 2004-10-03 at 16:24 -0700, Randolph Fritz wrote:

On Sun, Oct 03, 2004 at 04:16:40PM -0700, Randolph Fritz wrote:

Others don't. That code is intended to improve virtual memory
performance; such code is, unfortunately, system-dependent and belongs
in the non-existant bottle we need to keep system-dependent stuff.

Randolph

Randolph Fritz wrote:

>
> But you're right. Even if most compilers allow it, by the books
> it's not legal to do pointer arithmetic with void pointers.

Not exactly...it's "undefined".

That's the same thing for most pratical purposes.

  That code is intended to improve virtual memory
performance; such code is, unfortunately, system-dependent and belongs
in the non-existant bottle we need to keep system-dependent stuff.

I can't find anything system-dependent in that code, other
than it may help more on some platforms than on others.

-schorsch

···

--
Georg Mischler -- simulations developer -- schorsch at schorsch com
+schorsch.com+ -- lighting design tools -- http://www.schorsch.com/

Randolph Fritz wrote:

> >
> > But you're right. Even if most compilers allow it, by the books
> > it's not legal to do pointer arithmetic with void pointers.
>
> Not exactly...it's "undefined".

That's the same thing for most pratical purposes.

No, some environments (like gcc) define it. The problem is that it
only works in some environments and it cannot be counted on to work in
the same way in environments where it does work. "void *" does work
with gcc, whereas I'm not sure a "char *" version always will.

> That code is intended to improve virtual memory
> performance; such code is, unfortunately, system-dependent and belongs
> in the non-existant bottle we need to keep system-dependent stuff.

I can't find anything system-dependent in that code, other
than it may help more on some platforms than on others.

You have not had a youth wasted programming in too many weird
assembler languages! (At least, I hope not.) The "void *" version
only works if "void *" is the address of a byte in a contiguous
address space. That's actually not the case in some addressing models
on x86 machines, which is why the compiler rejects it. The "char *"
version depends on BYTES_WORD being correct. On, for instance, 64-bit
systems where "double" refers to a 128-bit quantity, it will allocate
a minimum of 16 bytes, rather than 8--a performance bug. More
seriously, one might encounter systems where the alignment requirement
is "long double" rather than "double", and future code which attempted
to cast the result of bmalloc() to "long double" would fail.

For the moment, I think, it is probably best to choose the type of
bposition with conditional compilation (wince), but I think in the
long run it's best to address the problem in a more general fashion; I
cannot enough stress how unreliable conditional compilation makes
cross-platform code.

Randolph, wishing he had more time to spend on Radiance

···

On Sun, Oct 03, 2004 at 08:12:56PM -0400, Georg Mischler wrote:

Randolph Fritz wrote:

"void *" does work with gcc, whereas I'm not sure a "char *"
version always will.

I'd think it's the other way round. The void* obviously doesn't
work everywhere. The char* works the way Greg originally intended.

This is so, because sizeof() is garanteed to return values relative
to the size of a char, whatever that is. And the size values
given as arguments to those two functions should always be determined
by sizeof() (as they should when you use plain malloc() and friends).

> > That code is intended to improve virtual memory
> > performance; such code is, unfortunately, system-dependent and belongs
> > in the non-existant bottle we need to keep system-dependent stuff.
>
> I can't find anything system-dependent in that code, other
> than it may help more on some platforms than on others.
>

You have not had a youth wasted programming in too many weird
assembler languages! (At least, I hope not.) The "void *" version
only works if...

The void* version was indeed system-dependent, as has been shown.

The char* version isn't. Maybe the exact size of the memory
chunks handed out would vary on 64 bit systems, but that's just
potentially suboptimal memory use, not a dependency.

Radiance is explicitly *not* 64 bit clean, and even if we were
to change that, this would probably be one of the simplest and
most obvious parts to optimize (after all the things that really
need to get fixed).

More
seriously, one might encounter systems where the alignment requirement
is "long double" rather than "double", and future code which attempted
to cast the result of bmalloc() to "long double" would fail.

So on some systems you won't be able to increment a char* pointer
anymore? I'm not quite as pessimistic... :wink:

-schorsch

···

--
Georg Mischler -- simulations developer -- schorsch at schorsch com
+schorsch.com+ -- lighting design tools -- http://www.schorsch.com/

ehmm, hmm,isn't this business a bit strange?

A question from someone who was lucky in NOT having its youth wasted
with weird asssembler languages :slight_smile:

What sense does it make incrementing a pointer when a priori you don't know anything about the entities it points to?

-cb

I searched "all over the place" for what people are
saying about void* and the concensus seems to be that
it is an old gcc-ism, inherited from the days when
type safety was not so important and sizeof(char)
arithmetic on void pointer was deemed a reasonable
default (even if, I would imagie, C people could also
reasonably expect it to be sizeof(int) by default).

Tony

···

--- Carsten Bauer <[email protected]> wrote:

ehmm, hmm,isn't this business a bit strange?

A question from someone who was lucky in NOT having
its youth wasted
with weird asssembler languages :slight_smile:

What sense does it make incrementing a pointer when
a priori you don't
know anything about the entities it points to?

__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com

When you are writing a storage alligator, er, allocator, it makes
perfect sense. Which is of course exactly what is under discussion.

Randolph

···

On Mon, Oct 04, 2004 at 10:58:59AM +0000, Carsten Bauer wrote:

ehmm, hmm,isn't this business a bit strange?

A question from someone who was lucky in NOT having its youth wasted
with weird asssembler languages :slight_smile:

What sense does it make incrementing a pointer when a priori you don't
know anything about the entities it points to?

On some current RISC systems you can't do so with impunity. For example:

  offset = 2;
  p = malloc(2*sizeof(double));
  dp = (double *) (p + offset);
  *dp = 1.0; /* runtime error */

I have little doubt that we will soon encounter RISC systems with
128-bit wide data buses that require offset to be 16. It is for this
reason that the results of void* arithmetic is undefined by the
standard; there is no way to define it that is fast, space-conserving,
and portable. At the same time, every C compiler supports some
version of unbound pointer arithmetic because it is required for
writing storage allocators like calloc()/malloc()/free().

I'd really rather not see more platform-dependent Radiance code.
Unfortunately, it at least used to be the case that
platform-dependencies made for substantial performance improvements.

My long-term recommendation on such matters has not changed: it is
best, first, to test for performance problems and use existing library
facilities where performance problems are absent, second, to to use
platform-dependent code in a clean way when it is of value.

Randolph

···

On Mon, Oct 04, 2004 at 04:20:47AM -0400, Georg Mischler wrote:

> More
> seriously, one might encounter systems where the alignment requirement
> is "long double" rather than "double", and future code which attempted
> to cast the result of bmalloc() to "long double" would fail.

So on some systems you won't be able to increment a char* pointer
anymore? I'm not quite as pessimistic... :wink:

The macro ALIGNT is set to the appropriate alignment type for the target system. All allocation pointers are aligned with this type in Radiance. The setting of this macro is controlled in makeall with the other (few) system-dependent settings.

···

From: Randolph Fritz <[email protected]>
Date: October 4, 2004 10:19:00 PM PDT

On Mon, Oct 04, 2004 at 04:20:47AM -0400, Georg Mischler wrote:

More
seriously, one might encounter systems where the alignment requirement
is "long double" rather than "double", and future code which attempted
to cast the result of bmalloc() to "long double" would fail.

So on some systems you won't be able to increment a char* pointer
anymore? I'm not quite as pessimistic... :wink:

On some current RISC systems you can't do so with impunity. For example:

  offset = 2;
  p = malloc(2*sizeof(double));
  dp = (double *) (p + offset);
  *dp = 1.0; /* runtime error */

I have little doubt that we will soon encounter RISC systems with
128-bit wide data buses that require offset to be 16. It is for this
reason that the results of void* arithmetic is undefined by the
standard; there is no way to define it that is fast, space-conserving,
and portable. At the same time, every C compiler supports some
version of unbound pointer arithmetic because it is required for
writing storage allocators like calloc()/malloc()/free().

I'd really rather not see more platform-dependent Radiance code.
Unfortunately, it at least used to be the case that
platform-dependencies made for substantial performance improvements.

My long-term recommendation on such matters has not changed: it is
best, first, to test for performance problems and use existing library
facilities where performance problems are absent, second, to to use
platform-dependent code in a clean way when it is of value.

Randolph

Still, writing that routine with "char *" is probably going to fail in
some environment, if it doesn't already. And we know writing it with
"void*" fails on MSVC.

I really, really, really would prefer to isolate platform-dependent
code.

Randolph

···

On Mon, Oct 04, 2004 at 10:27:55PM -0700, Greg Ward wrote:

The macro ALIGNT is set to the appropriate alignment type for the
target system. All allocation pointers are aligned with this type in
Radiance. The setting of this macro is controlled in makeall with the
other (few) system-dependent settings.

By your measure, every bit of code is system dependent and would have to be isolated.... This code has never failed, and given the ubiquity of char * for memory (and its long history in C), any compiler that choked on it would break 3/4 of Unix. The reason C is portable is because Unix is written in it, so it can't change arbitrarily from one implementation to the next. I still contend that it was MORE portable before ANSI came along than after, but that's another discussion.

-G

···

From: Randolph Fritz <[email protected]>
Date: October 4, 2004 10:34:44 PM PDT

On Mon, Oct 04, 2004 at 10:27:55PM -0700, Greg Ward wrote:

The macro ALIGNT is set to the appropriate alignment type for the
target system. All allocation pointers are aligned with this type in
Radiance. The setting of this macro is controlled in makeall with the
other (few) system-dependent settings.

Still, writing that routine with "char *" is probably going to fail in
some environment, if it doesn't already. And we know writing it with
"void*" fails on MSVC.

I really, really, really would prefer to isolate platform-dependent
code.

Randolph

As long as one restricted to porting machines with VAX-like addressing
and number sizes! But, no, I don't think all, or even most, of
Radiance is platform dependent.

Randolph

···

On Tue, Oct 05, 2004 at 08:35:11AM -0700, Greg Ward wrote:

By your measure, every bit of code is system dependent and would have
to be isolated.... This code has never failed, and given the ubiquity
of char * for memory (and its long history in C), any compiler that
choked on it would break 3/4 of Unix. The reason C is portable is
because Unix is written in it, so it can't change arbitrarily from one
implementation to the next. I still contend that it was MORE portable
before ANSI came along than after, but that's another discussion.

Greg Ward wrote:

By your measure, every bit of code is system dependent and would have
to be isolated.... This code has never failed, and given the ubiquity
of char * for memory (and its long history in C), any compiler that
choked on it would break 3/4 of Unix.

All C code using dynamic memory would break.

There's a very basic reason why char* is the correct choice here.
By definition, sizeof(char) == 1. This means that memory sizes
are always measured relative to the size of a char, while the
actual number of bits in a char is irrelevant. If this rule (or
an equivalent one) wasn't enforced, reliable memory handling
would be impossible, let alone in a platform-independent way.

-schorsch

···

--
Georg Mischler -- simulations developer -- schorsch at schorsch com
+schorsch.com+ -- lighting design tools -- http://www.schorsch.com/