A C without void*

P

Peter Nilsson

A good question, but one you probably should have asked in
isolation first. Find out what you're trying to solve before
proposing a solution.

It would mean more typing. That would be enough for me!

No, he's talking about a C without void *. void was obviously
brought in to allow functions that do not return values (what
other languages call procedures.) The decision to allow void *
was quite deliberate, but not such an obvious one!

Aesthetically the concept of a generic pointer sits better with
void * than unsigned char *, but I can't think of an obvious
practical reason why the latter wasn't adopted. It already was
the pseudo generic pointer type pre ANSI C, so it wouldn't have
harmed existing code too much, or presented a much different
(let alone difficult) paradigm.

I'd rather see a discussion on how generic programming in C
can be improved, than quibling over the base type for generic
pointers. But I think we already know the answer to that: if
you want C++ you know where to find it. ;)
 
B

BGB

In all the same ways that C++ is inferior to C. If his book is to be
believed, Stroustrup designed C++ to stop people from casting so much. The
type-intelligent OOP semantics were the carrot, and the ugly casting
notations--static_cast<>(), et al--were the stick.

But if you read actual C++ code in the wild, it's thick with explicit casts.
In fact, so much so that one would think the design must somehow
fundamentally encourage it.

On the other hand, I rarely see casting in C. Void pointers don't seem to be
abused or used much at all, in my experience. If used at all it's not to
acquire a different type for the reference, but merely for passing generic
objects.

Void pointers are the simple workaround to the caveats of strict typing.
C++'s typing semantics present the complex "solution". Both are an attempt
to provide a safer--compiler instrumented--workaround to strict typing than
explicit casting.

late to this party...

but:
elsewhere, I had a task where I was using lots of 'void *' pointers, but
with a conceptual type involved (dynamic types).

some time later, I added a typedef, since I wanted more
visual/contextual evidence that this was what I was doing.


later still, I switched the typedef to using an incomplete struct type,
mostly to limit spurious conversions to/from the type.

this was then followed by some changes to the API, to fix problems where
the API itself was being ambiguous (well, this function accepts/returns
one of some-N argument pointer types).

followed by large amounts of fixing code later to eliminate all the
resultant spurious warning messages (inserting casts, or switching to
the more appropriate API calls).


granted, "void *" is still nice for its intended purpose...
 
L

lawrence.jones

Peter Nilsson said:
Aesthetically the concept of a generic pointer sits better with
void * than unsigned char *, but I can't think of an obvious
practical reason why the latter wasn't adopted.

Using a new type allowed for greater type safety since it distinguishes
generic pointers (the rules for which are fast and loose) from char
pointers (which have much more restrictive rules).
 
B

BartC

William Ahern said:
Perhaps not cleaner, just more explicit. The problem with explicit is
sometimes you want to conflate the names.

outer:for() { if (x) continue outer; else goto outer; }

The suggestion was to use :: for loop labels. That's far better from a
language design point of view, it eliminates multiple labels per loop, means
goto cannot use the same labels, which would have a different meaning from
break or continue, and moving a loop around without it's label would more
likely generate syntax errors.

(It's possible the label can be attached to it's loop more solidly by
writing as for::eek:uter(...) for example. But while that makes things better
in some cases, in others the label has to stay independent:

for::eek:uter() while::inner()... break outer;

Here, it's possible the for/while loops can be swapped, but the outer and
inner labels should stay in the same order.)
If you couldn't conflate, you end up with

restart:
outer:for() { if (x) continue outer; else goto restart; }

I'm not sure that's cleaner. Sometimes clean means putting disparate
things
into a single box. If someone is interested in the box, they can
investigate. Otherwise, using a single box for every little item is just
clutter.

It starts to get messy. In one language design I used four loop controls:
'restart', 'redo', 'next' and 'exit'. The last two correspond to 'continue'
and 'break' in C, and are equivalent to gotos to these four labels in a
loop:

for (RESTART: i=start; i<=limit; NEXT:++i) { REDO: body;} EXIT:

(I've never used 'continue', but I assume it's a goto NEXT. On while loops,
some labels will coincide.)
 
K

Keith Thompson

BartC said:
The suggestion was to use :: for loop labels. That's far better from a
language design point of view, it eliminates multiple labels per loop, means
goto cannot use the same labels, which would have a different meaning from
break or continue, and moving a loop around without it's label would more
likely generate syntax errors.

I actually suggested "::" only as an illustration, and specifically
did not recommend using it. The reason: though it would be a
reasonable syntax for C, the feature would be equally useful in C++,
which uses "::" for different purposes.

Unless someone can think of a good light-weight syntax for loop
names that doesn't cause any conflicts, I think the best approach
is simply to re-use the existing label syntax. As I've said, Perl
does this (a choice that was made without any need to consider
backward compatibility), and it hasn't caused any real problems
that I'm aware of.

If I were designing C from scratch, I'd use the "name:" syntax
for loop names and pick something else, something more prominent,
for goto labels. But of course it's too late for that.

[...]
 
R

robertwessel2

And how does the single-colon syntax not do that?


As would a label with a for loop as it's statement.


A label is never independent because it must precede a statement. And a
compiler would easily see in the AST which type of stateement is attachedto
a label.


For compatibility a label attached to a loop statement would have to
be referenceable by a goto within that loop. Yes, goto, break and
continue to that label would all be possible, and would all do
different things. But all three things are well defined. The double
colon syntax* introduces a separate namespace for loop labels. But I
don't think it's necessary - any of the possible references to a label
should generally be used sparingly. Use of both goto and break/
continue to refer to the same label *could* be prohibited without
backwards compatibility problems, but again, I don't see any real
point.

*I don’t think that gratuitous an incompatibility with C++ would ever
be accepted, but that’s a different issue.
 
K

Keith Thompson

William Ahern said:
And how does the single-colon syntax not do that?

This:

label1:
label2:
while (1) { /* ... */ }

is already legal, and could not be made invalid without potentially
breaking existing code. On the other hand, this:

label1::
label2::
while (1) { /* ... */ }

could be a syntax error.

Still, I don't think this is a major issue. If a loop has multiple
labels, I suggest that a break or continue can use either of them
to refer to the loop. There's rarely, if ever, a good reason to
write code like that, but we don't need a special rule.

[...]
I don't follow. How is double-colon syntax less messy by itself?

It makes for a cleaner distinction between labels (targets of goto
statement) and loop names. Note that I wrote "loop *names*", not "loop
labels"; a loop name is a name for the entire loop, not for a single
point in the code.

I'd *like* to have the syntax reflect this distinction, but I can't
think of a clean way to do it.
 
B

BartC

I don't follow. How is double-colon syntax less messy by itself?

The double-colon thing is a red herring. The suggestion is really to use any
different syntax from a label definition, to annotate each loop, because
loop 'labels' (the term itself is causing the confusion) behave completely
differently, and are for a different purpose, from ordinary labels.

And being tied to a particular statement type, there is less chance of
inadvertently getting them mixed up with ordinary goto-labels. (On top of
that, if we see a dedicated label, we know there won't be some gotos to it
lurking anywhere the code; only the more innocuous break and continue in
*this* loop.)

(For the same sorts of reasons, we don't use ordinary labels for function
definitions.)

Also, a specialist loop 'label' can appear at the beginning *or* end of a
loop (since it's likely most uses will be to break out of it), or perhaps
both!

And I also made a suggestion, indirectly, that there might be more loop
controls:

- 'continue' perhaps split into two (does it go to the end of the loop body,
or the beginning?)
- 'restart', used with for-loops, to reinitialise loop variables, as the
temptation was to use goto on the loop 'label' to achieve that.

(And it goes without saying that an alternative to 'break' can be added,
which cannot be confused for a switch-break.)
 
R

robertwessel2

The syntax of 'break' and 'continue' would need to change (in a
backwards compatible way) but 'for', 'while' etc don't need to change.
For example:
   outer: for (int i = 0; i<  n; i++)
              for (int j = i; i<  n; j++)
                  if (A[j] == target)
                       break outer;


i don't like break and prefer goto
           i=0;
           outer:;
           for (  ; i<  n; i++)
               {for (j = i; i<  n; j++)
                   if (A[j] == target)
                        goto outer;
               }



Of course that does something completely different.
 
H

Hans Vlems

The syntax of 'break' and 'continue' would need to change (in a
backwards compatible way) but 'for', 'while' etc don't need to change.
For example:
   outer: for (int i = 0; i<  n; i++)
              for (int j = i; i<  n; j++)
                  if (A[j] == target)
                       break outer;


i don't like break and prefer goto
           i=0;
           outer:;
           for (  ; i<  n; i++)
               {for (j = i; i<  n; j++)
                   if (A[j] == target)
                        goto outer;
               }


Sorry, but I don't see the benefit of this. After all, there *is* already a
statement in the C language that does exactly that. It is called "goto", and
it solves exactly this situation.
So long,
Thomas- Tekst uit oorspronkelijk bericht niet weergeven -

- Tekst uit oorspronkelijk bericht weergeven -


Constructs like that might need a little more thought and you might
end up with a better algorithm.
Hans
 
R

robertwessel2

<m> ha scritto nel messaggio
"Thomas Richter" <[email protected]> ha scritto nel
messaggioOn 22.03.2011 22:40, Ben
Bacarisse wrote:
The syntax of 'break' and 'continue' would need to change (in a
backwards compatible way) but 'for', 'while' etc don't need to change.
For example:
outer: for (int i = 0; i< n; i++)
for (int j = i; i< n; j++)
if (A[j] == target)
break outer;

i don't like break and prefer goto
i=0;
outer:;
for ( ; i< n; i++)
{for (j = i; i< n; j++)
if (A[j] == target)
goto outer;
}


Of course that does something completely different.
--------------
i don't like break and prefer goto

 for (i=0 ; i< n; i++)
   {for (j = i; i< n; j++)
         if (A[j] == target)
                       goto outer;
    outer:;
   }

than the loop above is equivalent to

 for (i=0 ; i< n; i++)
   {for (j = i; ; j++)
         if (A[j] == target)
                       goto outer;
    outer:;
   }

i think it all a bug, the code in origin,
what the poster say about break etc etc



No, the original loop is equivalent to:

for (i=0 ; i< n; i++)
{for (j = i; ; j++)
if (A[j] == target)
goto outer;
}
outer:;
 
R

robertwessel2

robertwessel2 ha scritto nel messaggio
<m> ha scritto nel
messaggio"Thomas Richter" <[email protected]> ha scritto nel
messaggioOn 22.03.2011 22:40, Ben
Bacarisse wrote:
The syntax of 'break' and 'continue' would need to change (in a
backwards compatible way) but 'for', 'while' etc don't need to change.
For example:
outer: for (int i = 0; i< n; i++)
for (int j = i; i< n; j++)
if (A[j] == target)
break outer; ...
than the loop above is equivalent to
for (i=0 ; i< n; i++)
{for (j = i; ; j++)
if (A[j] == target)
goto outer;
outer:;
}


the above if there is no target in A[j] is a never
end loop
No, the original loop is equivalent to:
for (i=0 ; i< n; i++)
  {for (j = i; ; j++)
        if (A[j] == target)
                      goto outer;
  }
outer:;


Grazie molte
thank you
i not understood that, in the above language hipotesis
on add in the standard a break loop like a label,
the "break outer;" means "break" the first for loop
[the one where "outer" point;
 "outer: for (int i = 0; i< n; i++)" ]



More precisely it would mean break the loop labeled "outer". In C,
the label is part of a statement, so in "outer: for(..." the label
"outer" is part of the for statement. If you used "outer: ; for(...",
the label would be on the empty statement (";"), and you could not
break to that.
 
D

David Thompson

If I were designing C from scratch, I'd use the "name:" syntax
for loop names and pick something else, something more prominent,
for goto labels. But of course it's too late for that.
FWIW Ada did just that, using <<label>> to make goto targets ugly,
much like Stroustrup's reinterpret_cast<...> et al in C++.

Of course Ada started about 8 years later, and from a clean slate.
 
K

Keith Thompson

David Thompson said:
FWIW Ada did just that, using <<label>> to make goto targets ugly,
much like Stroustrup's reinterpret_cast<...> et al in C++.

Of course Ada started about 8 years later, and from a clean slate.

Yes, Ada inspired the idea (lest anyone think I'm claiming to be
original).
 
M

MikeP

Spiros said:
Why does C have void* ? Imagine a C' where the functionality that
void* provides would be provided instead by unsigned char* plus what
unsigned char* usually does. In what way would C' be inferior to C ?''

Well you fucked up that question royally.
 
M

MikeP

Spiros said:
Why does C have void* ? Imagine a C' where the functionality that
void* provides would be provided instead by unsigned char* plus what
unsigned char* usually does. In what way would C' be inferior to C ?

THINK, before you speak. Oops, nevermind. Carry on, or not. Isn't it for
you to THINK and rarely to SAY?
 
K

Keith Thompson

MikeP said:
Well you fucked up that question royally.

The question was posted over 3 months ago. Why are you responding with
this nonsense now?

For that matter, why are you posting here at all? Do you intend to make
any constructive contributions here?
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,091
Messages
2,570,604
Members
47,223
Latest member
smithjens316

Latest Threads

Top