O
Old Wolf
In my humble view, the ideal solution would be:1) void* is a generic pointer type that can be implicitly converted
to/from any other object that can be dereferenced at least !once!
(e.g. char*, int*, also char**, int**, but not char,int)
2) void** is a generic pointer type [...]
We have a generic pointer type: void *
What if you want to point to one of these generic pointers?
And you are a person who thinks type-safety has advantages
(which is presumably why you chose C instead of Perl for
your program).
You want to have a non-generic pointer that can point to
generic pointers.
After all, if you wanted to use a generic pointer to point to
a generic pointer.... you would just use the generic pointer
you already have.
The designers of C presumably followed this logic, and
decided that void ** should be a pointer to void* (and not
a pointer to anything else).
there are two types of programming brains:
#define FOOS 10
struct
{ int i;
double d;
char *p; } *foo;
foo=calloc(FOOS,sizeof(*foo));
Looking at the piece of code above, brain type A will cry in pain
and quickly change the wrong code to read
foo=malloc(FOOS*sizeof(*foo));
for (i=0;i<FOOS;i++)
{ foo.i=0;
foo.d=0;
foo.p=NULL; }
And then, there's brain type B who sees that the 'correct' version
takes 5 lines instead of 1, reduces readability, maintainability, can be
a source of additional errors and wastes developer life time.
Type B simply uses the 'elegant' calloc approach and trusts in the
laws of physics:
Well, if I were an employer I'd rather have programmer B work for me.
I guess you have never had to port an application from one
platform, to another substantially different one.
In fact I would prefer programmer D who writes:
struct bar
{
int i;
double d;
char *p;
};
static struct bar const bar_defaults = { 0 };
struct bar *p_foo = malloc( FOOS * sizeof *p_foo );
if (!p_foo) do_something.....
for (size_t i = 0; i != FOOS; ++i)
p_foo = bar_defaults;
which avoids the problem of the structure being updated later
and the initialization step forgotten. Also it allows for a field
to have a non-zero default value, something which is
impossible in the inflexible B-brain version.
Further, if the defaults is indeed all bits zero, the compiler
will be likely to generate a memset instruction (or even
call calloc).
even if one night, someone drunk and stoned
creates an architecture that requires the long version,
it will be forced to play a marginal niche role, since an architecture
that is so inherently inefficient that it requires five times as much
code cannot rule the world.
Who measures an architecture's efficiency in lines of C code ??
I think you would get on well with Paul Hsieh (another regular
poster here who thinks that not only is catering for non-x86 a
waste of time, but he must also admonish anybody else who
does it).