C as a Subset of C++ (or C++ as a superset of C)

B

BGB

Am 29.08.2012 00:03, schrieb Leigh Johnston:

That could well be possible. Did you read the previous discussion?
Otherwise your statement doesn't qualify for much more intelligence
than mine.

I just would prefered to have a reason that goes beyond something like
"we tradionally use void* like this". I still didn't get a consistent
reply why "void*" is needed in C++ (but for compability with C and for
"operator new").

compatibility with C would be the main thing here.

if the languages were merged, presumably everyone on both sides would
want their code to still work, preferably unmodified.

if it were a case where most existing C code broke, people wouldn't be
happy, and would just stay with C.


if it were a case where C++ were broke, then C++ people wouldn't be
happy, and would just stick with C++.

like, say, what if we renamed all of C++'s keywords, and made them
special defines where you had to include headers to enable them:
#include <stdclass.h>
#include <stdtemplate.h>
....

class Foo:IBar { ... };

otherwise it was just _Class and _Template and _Namespace and similar?...


a person could just be like "well, it is a trivial change, but go add
these here includes to every source-file and header which uses C++
related extensions".

as well as possibly needing a keyword for overloaded functions:
overload int foo(int x) { ... }
overload int foo(double x) { ... }
....

to be like "hey, this one might need name mangling!"

and, maybe classes are defined to have a strict mapping to structs
similar to that of COM objects, ...

it would likely be a no-go for C++ developers as well.


even if it were something as minor as adding:
#include <stdcplusplus.h>

to just a few files...


so, a compromise would likely be needed on many points.


It still seems that such discussions aren't possible and that at least
some people just react with ideology.

hopefully, I think at least I am more thinking in terms of being
pragmatic, even if, yes, such a merge is unlikely.

IMO, it is more the place of a language to provide a set of mechanisms,
not enforce any particular mindset or ideology.

What higher entity revealed you that commandment?

ironically, I do remember seeing C++ code in the past using "char *" for
many things which C people would normally use "void *" for.

"void *" makes a few stronger guarantees, which may be something at least.
 
J

James Kuyper

On 08/29/2012 01:08 PM, BGB wrote:
....
ironically, I do remember seeing C++ code in the past using "char *" for
many things which C people would normally use "void *" for.

"void *" makes a few stronger guarantees, which may be something at least.

In C, there's trade-off: [[un]signed]char* can be dereferenced and
supports pointer arithmetic, while void* allows implicit conversion to
and from other types. That makes void* the appropriate type for pointers
to objects of unspecified types, and unsigned char* the appropriate type
for treating an object as if it were an uninterpreted array of bytes.

C++ templates replace the need to treat objects of unspecified types
with the ability to treat objects of arbitrary type. Removing the
implicit conversion from void* to T* removes some (but not quite all) of
the remaining value of supporting void*.
 
J

James Kuyper

On 08/29/2012 02:16 PM, Leigh Johnston wrote:
....
... The lack of
implicit conversion *from* void* does not change the utility of void*.

In C, implicit conversion to and from void* is the only feature that
void* has that justifies using it instead unsigned char*. In C++, half
of those implicit conversions are missing, and no compensating advantage
has been added to void*. How could it NOT change the utility?
 
J

Jens Gustedt

Am 29.08.2012 17:12, schrieb Casey Carter:
ISO 14882-2011 5.2.9/13 (static_cast) says:

...A value of type pointer to object converted to "pointer to cv void"
and back, possibly with a different cv-qualification, shall have its
original value.

C has a similar phrase. But that only states that you may use "void*".
It doesn't state that you can't use any other. Or you read here
something like "thou shalt only use void* for low level implementations" ?

In C at least, any object pointer can be cast back and forth to any
other object pointer and there is only UB if there are alignment
problems. "unsigned char*" always has the least possible alignment so
you can basically use it for that (or any of the two other character
types). And traditionally in early C (and C++ also, I suppose) it had
been "char*".

Jens
 
J

Jens Gustedt

Am 29.08.2012 20:16, schrieb Leigh Johnston:
char* is .. wait for it .. a pointer to char; void* is .. wait for it ..
a pointer to anything;

and so what is "char" for you? or "unsigned char". For me "unsigned
char" is the smallest adressable storage unit for C and C++ programs
that, for convenience, also has the property of an unsigned integer
type such that we may inspect all of its bits. So pointer to "unsigned
char" is a pointer to the smallest uninterpreted storage unit that the
language(s) provide.
this has not changed from C to C++. The lack of
implicit conversion *from* void* does not change the utility of void*.

For C programmers it does make "void*" useless.

So implicitly you are claiming that it utility for C++ lays in that
fact that any object pointer converts to "void*" even without a cast?

(Without that all the C library function would be very cumbersome to
use, indeed.)

Do you often see a "void*" in a veritable C++ interface, I mean in one
that could not be defined with 'extern "C"' and then entirely
implemented in C?

(and I don't mean it to be provocative, I really want to know)

Jens
 
J

James Kuyper

Having to use an explicit cast when converting from void* in C++ is not
a problem; in fact it is an advantage: you are less likely to create a
bug. void* has as much utility in C++ as it has in C.

I was very explicitly talking about advantages of void* in comparison
with character pointer types, and this isn't one of them. [[un]signed]
char* has that exact same feature, so why bother with void*?
 
C

Casey Carter

Having to use an explicit cast when converting from void* in C++ is not
a problem; in fact it is an advantage: you are less likely to create a
bug. void* has as much utility in C++ as it has in C.

I was very explicitly talking about advantages of void* in comparison
with character pointer types, and this isn't one of them. [[un]signed]
char* has that exact same feature, so why bother with void*?

In C++, I cannot pass a void* as argument to a function that expects an
[[un]signed] char* without casting. If you don't see this as a feature,
then I understand why you think void* in C++ has no purpose.
 
J

James Kuyper

On 29/08/2012 19:34, James Kuyper wrote:
On 08/29/2012 02:16 PM, Leigh Johnston wrote:
...
... The lack of
implicit conversion *from* void* does not change the utility of void*.

In C, implicit conversion to and from void* is the only feature that
void* has that justifies using it instead unsigned char*. In C++, half
of those implicit conversions are missing, and no compensating advantage
has been added to void*. How could it NOT change the utility?

Having to use an explicit cast when converting from void* in C++ is not
a problem; in fact it is an advantage: you are less likely to create a
bug. void* has as much utility in C++ as it has in C.

I was very explicitly talking about advantages of void* in comparison
with character pointer types, and this isn't one of them. [[un]signed]
char* has that exact same feature, so why bother with void*?

In C++, I cannot pass a void* as argument to a function that expects an
[[un]signed] char* without casting. If you don't see this as a feature,
then I understand why you think void* in C++ has no purpose.

"Why bother with void*?" was an exaggeration - I should have said that
less provocatively. I was not actually arguing that void* has no value
in C++, only that it has less value in C++ than it has in C, where it
has two advantages relative to unsigned char*, instead of only one.
Also, as I mentioned in other messages (though not quoted here), in C++
templates take care of many things for which void* would be needed in C.
 
J

James Kuyper

On 29/08/2012 19:34, James Kuyper wrote:
On 08/29/2012 02:16 PM, Leigh Johnston wrote:
...
... The lack of
implicit conversion *from* void* does not change the utility of void*.

In C, implicit conversion to and from void* is the only feature that
void* has that justifies using it instead unsigned char*. In C++, half
of those implicit conversions are missing, and no compensating advantage
has been added to void*. How could it NOT change the utility?

Having to use an explicit cast when converting from void* in C++ is not
a problem; in fact it is an advantage: you are less likely to create a
bug. void* has as much utility in C++ as it has in C.

I was very explicitly talking about advantages of void* in comparison
with character pointer types, and this isn't one of them. [[un]signed]
char* has that exact same feature, so why bother with void*?

In C++, I cannot pass a void* as argument to a function that expects an
[[un]signed] char* without casting. If you don't see this as a feature,
then I understand why you think void* in C++ has no purpose.

"Why bother with void*?" was an exaggeration - I should have said that
less provocatively. I was not actually arguing that void* has no value
in C++, only that it has less value in C++ than it has in C, where it
has two advantages relative to unsigned char*, instead of only one.
Also, as I mentioned in other messages (though not quoted here), in C++
templates take care of many things for which void* would be needed in C.
 
B

Bo Persson

Jens Gustedt skrev 2012-08-29 00:07:
Am 28.08.2012 20:38, schrieb Bo Persson:

No I was asking a question to somebody and not necessarily promoting
that idea. The starting point of that discussion was seeking a way to
be able to access a buffer in "typeless" chunks that correspond to the
common object types that a particular architecture might
have. Seemingly the word "mandatory" provoked some allergic reaction.

Would it be more acceptable for you to have different names for such
beasts (say void8_t, void16_t etc) or would you be ok to mandate
uintXX_t where XX are some multiples of CHAR_BIT?


I don't really care what they are called :), I just wanted to point out
that any changes to the languages to make them stricter and more
portable, will also affect people who don't intend to make their code
portable at all, because they just cannot anyway.

In another post I mentioned that we use IBM mainframes. The code written
on those depends heavily on the transaction manager of the z/OS (IMS),
and the availability of large DB2 databases. This is mission critical
for many companies.

When we code in "very portable" Java (we do that to, for web services),
we have to add special support hardware to comply with the JVM
specification of its data types. Hardware accelerators for the Java code!

When we code in other languages, it runs natively on the existing
hardware. It is allowed to be big endian, and even use non-IEEE floating
point!

The code we have is not portable anywhere else, not even the Java code,
because it is totally dependent on the surrounding infrastructure.

Having some features "mandatory" for the ease of portability, does
provoke an allergic reaction. Please just let us continue to write our
non-portable code, and write your portable code targeting all other
systems.

We are not interested in low level portability, because that is not a
feature we have any use for. It might add extra cost though, if it is
made mandatory like in Java. :-(


Bo Persson
 
J

Jens Gustedt

Am 29.08.2012 21:09, schrieb Leigh Johnston:
So malloc is useless?

not in C, where implicit conversion from "void*" works without
problems

or where you refering to C++? using malloc? doesn't that give you
objects for which the constructor isn't called :)
Use void* when you need an untyped pointer; such needs exist in both C
and C++.

you don't answer my question, still no example for a real use case in
C++, could you be more concrete?

Jens
 
J

Jens Gustedt

Am 29.08.2012 22:43, schrieb Leigh Johnston:
Ergo void* is not useless in C.

Where did you read that? I didn't say that. I am just, almost
desperately seeking someone who wants to present me with a real use
case in C++.

It has a lot of good use cases in C. It would lose most of its use in
C, if it wouldn't implicitly convert to any other pointer to object
type.
I never use malloc in a C++ program.
see


Example: a pointer to an object associated with in an item in a GUI list
box widget. In the GUI library I am currently creating the list box
widget is actually a template however the item data type defaults to
void* as both a convenience and a way to reduce template bloat; however
lots of GUI libraries solely use void* for such things (e.g. Microsoft
Win32 API).

Then they are no good C++. These things can be done in C++ without any
loss of performance and with much more type safety by using templates,
inheritance, all that machinery.

So you gave me an example where "void*" encourages bad design, is
that?

My claim would be that *if* you want to play such "dirty tricks"
create a proper interface and then program the beast itself in C.
Another example: an object pointer passed to /pthread_create/.

That doesn't count, pthread_create (or better the new and shiny
thrd_create) are C interfaces. They are designed as such. That is not
a proper use case for C++.

Jens
 
C

Casey Carter

That doesn't count, pthread_create (or better the new and shiny
thrd_create) are C interfaces. They are designed as such. That is not
a proper use case for C++.

Ok, how should I pass data through pthread_create in C++ if you won't
allow me to use void*?

This discussion seems to be pointless when we give examples of use cases
for void* in C++ and you respond with "that doesn't count." Perhaps you
could better explain your criteria for what a valid use might be?
 
K

Keith Thompson

Jens Gustedt said:
No, this is not an "unwritten rule" for C. C99 originally had a
wording that could be interpreted as you state. A corrigendum has made
it clear that it is not intended. Type-punning in C works as long as
the value that you are reading is valid for the type through which you
are doing so.

A footnote in the C standard clarifies that:

95) If the member used to read the contents of a union object is not
the same as the member last used to store a value in the object, the
appropriate part of the object representation of the value is
reinterpreted as an object representation in the new type as described
in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be
a trap representation.

Yes. That footnote was added by Technical Corrigendum 3. It appears
in N1256 (though oddly without a change bar), and of course in C11
(or at least N1570).

[...]
 
L

Luca Risolia

Nonsense; you must have skipped where I used the words "template bloat";
even Stroustrup advocates this method (see TC++PL 13.5 Specialization).

That is a valid use of void*, although some modern compilers are smart
enough to avoid code bloat without that kind of help.
 
K

Keith Thompson

James Kuyper said:
On 08/29/2012 02:16 PM, Leigh Johnston wrote:
...

In C, implicit conversion to and from void* is the only feature that
void* has that justifies using it instead unsigned char*. In C++, half
of those implicit conversions are missing, and no compensating advantage
has been added to void*. How could it NOT change the utility?

Another feature of void* is that it prevents you from dereferencing
it or performing pointer arithmetic on it. (Unless you're using
gcc without one of the "-std=..." or "-ansi" options.)
 
A

Adrian Ratnapala

x = f;
y = * (reinterpret_cast <unsigned int*> &x);

My C++ casting-fu is weak, but I would have thought

y = reinterpret_cast<unsigned int>(f)

would do the job, because reinterpret_cast is explicitly about
preserving the bit pattern anyway, there is no need to play around with
memory addresses. Of course the C style cast (unsigned int)f is totally
different.
 
C

Casey Carter

My C++ casting-fu is weak, but I would have thought

y = reinterpret_cast<unsigned int>(f)

would do the job, because reinterpret_cast is explicitly about
preserving the bit pattern anyway, there is no need to play around with
memory addresses. Of course the C style cast (unsigned int)f is totally
different.

Casting from floating point to integral type is not within the purview
of reinterpret_cast. From C++11 5.2.10, the possible conversions are
* pointer to integral
* integral to pointer
* function pointer to different function pointer
* object pointer to different object pointer
* function pointer to object pointer (and vice versa) with
implementation-defined semantics
* pointer to member-function to different pointer to member-function
* pointer to data member to different pointer to data member
* reference to different reference where the pointer conversion is
defined (i.e., reinterpret_cast<T&>(u) is defined to be the same as
*reinterpret_cast<T*>(&u)) [footnote actually refers to this as type
punning]

The type pun from the OP is then simply:

unsigned int foo(float f) {
return reinterpret_cast<unsigned int&>(f);
}

or - since I'm a C++ programmer and I like to overcomplicate things:

template <typename Target, typename Source>
Target& pun_as(Source& s) {
return reinterpret_cast<Target&>(s);
}

so I can simply write

pun_as<unsigned int>(some_float) = 21369U;
 
J

Jens Gustedt

Am 30.08.2012 00:21, schrieb Leigh Johnston:
You said "For C programmers it does make "void*" useless.". malloc uses
void* and malloc is used by C programmers ergo void* is not useless to C
programmers.


Correct; perhaps this is what you meant.

Yes, this is what I said.
See what? I don't use malloc because new is superior and idiomatic.

Sure. So you don't need to operate on "void*" in C++.
Nonsense; you must have skipped where I used the words "template bloat";
even Stroustrup advocates this method (see TC++PL 13.5 Specialization).

so if you have Stroustrup's blessing, bad design is ok?
Of course it is a proper use case for C++; /pthread_create/ is callable
from C++.

You seem to have extreme difficulties or lack of willingless to read
what I say.

I said that "void*" is there for interface compatibility with C. So
sure, you might call a C function that has a "void*" parameter. This
is using "void*" as a data sink, you should (almost) never be tempted
to convert it back.

So again give me a proper use case in C++ that isn't just for calling
a C interface.

Jens
 
J

Jens Gustedt

Am 30.08.2012 00:21, schrieb Casey Carter:
Ok, how should I pass data through pthread_create in C++ if you won't
allow me to use void*?

This is not what I said and what the discussion was about. The
starting point was to seek proper use cases of "void*" for C++ that
are not just interfacing to C. Sure that you should be able to call C
functions, so you need "void*" there. Please give me *other* valid use
cases.

For the moment I only have been given

- calling C interfaces
- cases where "template bloat" (not my wording) made template
solutions impractical

Jens
 

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

Forum statistics

Threads
474,079
Messages
2,570,574
Members
47,205
Latest member
ElwoodDurh

Latest Threads

Top