f



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

Isn't it a lame use of human time and effort to maintain completely separate 
C and C++ standards? As in the words of Betty White about Facebook: "It 
seems like an incredible waste of time". Why don't the two standards groups 
get together and agree on a common specification for the ground which both 
standards cover? There would still be two separate standards, but they'd 
both be exactly the same for the common ground. The common ground document 
could be referred to by both standards instead of being maintained by both 
groups in individual efforts resulting in different verbage in separate 
specifications for the same functionality. This should happen after both 
groups agree to completely align the C subset functionality on the next 
realease of standards (e.g., VLAs? No one using them? Drop 'em in the name 
of cooperation going forward). 


0
tinker454 (114)
8/26/2012 9:57:30 AM
comp.lang.c++ 49423 articles. 7 followers. Post Follow

263 Replies
3610 Views

Similar Articles

[PageSpeed] 58

On 26.08.2012 11:57, Ansel wrote:

> This should happen after both 
> groups agree to completely align the C subset functionality on the next 
> realease of standards (e.g., VLAs? No one using them? Drop 'em in the name 
> of cooperation going forward). 

Ever heared of printf?

Best regards,
Johannes

-- 
>> Wo hattest Du das Beben nochmal GENAU vorhergesagt?
> Zumindest nicht �ffentlich!
Ah, der neueste und bis heute genialste Streich unsere gro�en
Kosmologen: Die Geheim-Vorhersage.
 - Karl Kaos �ber R�diger Thomas in dsa <hidbv3$om2$1@speranza.aioe.org>
0
dfnsonfsduifb (1191)
8/26/2012 10:28:31 AM
Le 26/08/12 11:57, Ansel a �crit :
> Isn't it a lame use of human time and effort to maintain completely separate
> C and C++ standards? As in the words of Betty White about Facebook: "It
> seems like an incredible waste of time". Why don't the two standards groups
> get together and agree on a common specification for the ground which both
> standards cover? There would still be two separate standards, but they'd
> both be exactly the same for the common ground. The common ground document
> could be referred to by both standards instead of being maintained by both
> groups in individual efforts resulting in different verbage in separate
> specifications for the same functionality. This should happen after both
> groups agree to completely align the C subset functionality on the next
> realease of standards (e.g., VLAs? No one using them? Drop 'em in the name
> of cooperation going forward).
>
>

You said in a message posted just 3 hours ago:

<quote>
It's hard to be enthusiastic about boring old C though. Yeah, it may be
the simplest way to deliver a library of simple functions, but so what?

Why bother worrying about the lonely C standard when C++ is almost a
superset of it and you're using a C++ compiler anyway?
<end quote>

Take you own advice dude and stop trolling

0
jacob31 (877)
8/26/2012 10:32:56 AM
jacob navia wrote:
> Le 26/08/12 11:57, Ansel a �crit :
>> Isn't it a lame use of human time and effort to maintain completely
>> separate C and C++ standards? As in the words of Betty White about
>> Facebook: "It seems like an incredible waste of time". Why don't the
>> two standards groups get together and agree on a common
>> specification for the ground which both standards cover? There would
>> still be two separate standards, but they'd both be exactly the same
>> for the common ground. The common ground document could be referred
>> to by both standards instead of being maintained by both groups in
>> individual efforts resulting in different verbage in separate
>> specifications for the same functionality. This should happen after
>> both groups agree to completely align the C subset functionality on
>> the next realease of standards (e.g., VLAs? No one using them? Drop
>> 'em in the name of cooperation going forward).
>
> You said in a message posted just 3 hours ago:
>
> <quote>
> It's hard to be enthusiastic about boring old C though. Yeah, it may
> be the simplest way to deliver a library of simple functions, but so
> what?
> Why bother worrying about the lonely C standard when C++ is almost a
> superset of it and you're using a C++ compiler anyway?
> <end quote>
>

But this new topic is an adjunct to that thought (which was meant in the 3rd 
person). Go to bed if you are crabby. 


0
tinker454 (114)
8/26/2012 11:10:42 AM
Am 26.08.2012 11:57, schrieb Ansel:

> Isn't it a lame use of human time and effort to maintain completely
> separate C and C++ standards?

yes

> The common ground document could be referred to by both standards
> instead of being maintained by both groups in individual efforts
> resulting in different verbage in separate specifications for the
> same functionality. This should happen after both groups agree to
> completely align the C subset functionality on the next realease of
> standards (e.g., VLAs? No one using them? Drop 'em in the name of
> cooperation going forward).

I don't know all the history, but maybe one of the reasons that it
didn't work so far is because some people bring their axe to the
discussion instead of burying it outside? I already sense the flames
from the people heating up and not recognizing that this is a thread
in two different news groups.

There already is a large corpus of standards that use the C standard
as their base, namely POSIX. It has some general clause that
everything that is described there and that is in contradiction with
the C standard is unintentional. (Don't know how this will work out in
future since C adopted the same thread extension as C++ which is
not completely interface compatible with POSIX. They really receive a
warm greeting from us all.)

POSIX avoided to *use* the parts of C that don't seem of their liking,
such as e.g variably modified types, that's all, and it works
satisfactory, I think. C has swallowed the pill already and declared
parts optional. For the variably modified types part, unfortunately it
only has made VLA optional as a whole, instead of distinguishing
between the possibility of instantiations of VLA and pointers to VLA
(VM types) which have a much more general use.

As the languages have evolved now, there are technical issues that
really would need a lot of compromise such that they could work out
well enough for both communities, you probably all know them,
different concepts of lvalues and rvalues, different sizeof of
literals, different default initializers, different concepts of
compile-time constants, different concepts of union, etc etc

Doing so would need people with good technical and social skills from
both communities. Not the kind of self-opinionated "experts" that we
often meet in discussions like this one.

Jens
0
8/26/2012 12:16:34 PM
As long as libraries like POSIX etc are willing to migrate, I vouch for single standard to cover both, ++ anyway is superset of C.
0
8/26/2012 4:38:39 PM
On Sun, 26 Aug 2012 03:57:30 -0600, "Ansel"
<tinker454@trytospammenowloser.com> wrote:

>Isn't it a lame use of human time and effort to maintain completely separate 
>C and C++ standards? As in the words of Betty White about Facebook: "It 
>seems like an incredible waste of time". Why don't the two standards groups 
>get together and agree on a common specification for the ground which both 
>standards cover? There would still be two separate standards, but they'd 
>both be exactly the same for the common ground. The common ground document 
>could be referred to by both standards instead of being maintained by both 
>groups in individual efforts resulting in different verbage in separate 
>specifications for the same functionality. This should happen after both 
>groups agree to completely align the C subset functionality on the next 
>realease of standards (e.g., VLAs? No one using them? Drop 'em in the name 
>of cooperation going forward). 

What is your recommended compromise for malloc?  

     Should C++ give up its strict type checking and no longer require
a cast of the return value?

or

     Should C now require the cast and break more than 20 years of
existing code?

-- 
Remove del for email
0
schwarzb3978 (1424)
8/26/2012 5:03:01 PM
Le 26/08/12 11:57, Ansel a �crit :
> Isn't it a lame use of human time and effort to maintain completely separate
> C and C++ standards? As in the words of Betty White about Facebook: "It
> seems like an incredible waste of time". Why don't the two standards groups
> get together and agree on a common specification for the ground which both
> standards cover? There would still be two separate standards, but they'd
> both be exactly the same for the common ground. The common ground document
> could be referred to by both standards instead of being maintained by both
> groups in individual efforts resulting in different verbage in separate
> specifications for the same functionality. This should happen after both
> groups agree to completely align the C subset functionality on the next
> realease of standards (e.g., VLAs? No one using them? Drop 'em in the name
> of cooperation going forward).
>
>

sizeof('b') is sizeof(int) int C, 1 in C++

Which one would you compromise on?

You do not know what you are talking about dude...
0
jacob31 (877)
8/26/2012 5:54:52 PM
Johannes Bauer <dfnsonfsduifb@gmx.de> writes:
> On 26.08.2012 11:57, Ansel wrote:
>> This should happen after both 
>> groups agree to completely align the C subset functionality on the next 
>> realease of standards (e.g., VLAs? No one using them? Drop 'em in the name 
>> of cooperation going forward). 
>
> Ever heared of printf?

You mean the standard C++ function declared in <cstdio>?
Yes, I've heard of it; why do you ask?

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
8/26/2012 8:56:02 PM
On 26/08/2012 19:54, jacob navia wrote:
> Le 26/08/12 11:57, Ansel a �crit :
>> Isn't it a lame use of human time and effort to maintain completely
>> separate
>> C and C++ standards? As in the words of Betty White about Facebook: "It
>> seems like an incredible waste of time". Why don't the two standards
>> groups
>> get together and agree on a common specification for the ground which
>> both
>> standards cover? There would still be two separate standards, but they'd
>> both be exactly the same for the common ground. The common ground
>> document
>> could be referred to by both standards instead of being maintained by
>> both
>> groups in individual efforts resulting in different verbage in separate
>> specifications for the same functionality. This should happen after both
>> groups agree to completely align the C subset functionality on the next
>> realease of standards (e.g., VLAs? No one using them? Drop 'em in the
>> name
>> of cooperation going forward).
>>
>>
>
> sizeof('b') is sizeof(int) int C, 1 in C++
>
> Which one would you compromise on?
>
> You do not know what you are talking about dude...

There are a few issues where C and C++ are different - but there are 
actually very few situations where well-written C99 C is not also close 
to valid C++, except perhaps where the C code uses reserved words from 
C++ as identifiers.  Add a few extra casts around things like malloc() 
and it is even closer.

Take your example here.  Yes, it is true that a character literal is an 
"int" in C and a "char" in C++.  But can you give me an example of 
useful, well-written C or C++, where the code is reasonably portable and 
passes reasonable warning checks (such as "-Wall" on gcc), and for which 
this difference is relevant?

Most of the features of C that are not in C++ are either old styles 
(such as omitting prototypes, or "implicit int") which are best avoided, 
or they are features that could be happily included in C++ (such as 
"long long", designated initialisers, etc.)


0
david2384 (2168)
8/26/2012 9:00:17 PM
David Brown <david@westcontrol.removethisbit.com> writes:
[...]
> Most of the features of C that are not in C++ are either old styles 
> (such as omitting prototypes, or "implicit int") which are best avoided, 
> or they are features that could be happily included in C++ (such as 
> "long long", designated initialisers, etc.)

Implicit int was dropped by C99.  Old-style (non-prototype) function
declarations have been "obsolescent" since 1989, but as of 2011 the
committee hasn't gotten around to removing them from the language;
*if* there were an effort to make C a struct subset of C++, requiring
prototypes wouldn't be a major obstacle.

C++11 added long long.  It didn't add designated initializers,
compound literals, "restrict", or VLAs (the latter are optional
in C11).

But I'm not at all convinced that redefining C as a strict subset
of C++ would be worth the effort.  In particular, C permits a void*
expression to be implicitly converted to another pointer type;
C++ does not.  Making C adopt the C++ rule would break tons
of existing code (struct foo *ptr = malloc(N * sizeof *ptr)).
I'm less sure about the consequence of making C++ adopt the C rule,
but I suspect it would break something having to do with templates
and/or overloading.

The two committees do make some effort to avoid too many
incompatibilities -- and I'd *like* to see C++ adopt a few more
C99 and C11 features than it has so far.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
8/26/2012 9:19:50 PM
On 26/08/2012 23:19, Keith Thompson wrote:
> David Brown <david@westcontrol.removethisbit.com> writes:
> [...]
>> Most of the features of C that are not in C++ are either old styles
>> (such as omitting prototypes, or "implicit int") which are best avoided,
>> or they are features that could be happily included in C++ (such as
>> "long long", designated initialisers, etc.)
>
> Implicit int was dropped by C99.  Old-style (non-prototype) function
> declarations have been "obsolescent" since 1989, but as of 2011 the
> committee hasn't gotten around to removing them from the language;
> *if* there were an effort to make C a struct subset of C++, requiring
> prototypes wouldn't be a major obstacle.

Agreed.

>
> C++11 added long long.  It didn't add designated initializers,
> compound literals, "restrict", or VLAs (the latter are optional
> in C11).

And is there any reason why C++ does not support these features?  They 
are useful, and should not detract from the language.

>
> But I'm not at all convinced that redefining C as a strict subset
> of C++ would be worth the effort.  In particular, C permits a void*
> expression to be implicitly converted to another pointer type;
> C++ does not.  Making C adopt the C++ rule would break tons
> of existing code (struct foo *ptr = malloc(N * sizeof *ptr)).

I suspect this is the biggest single incompatibility.  But I don't see 
anything against letting that stand - the key point is to make the 
future of C and C++ compatible, not to change old standards.

> I'm less sure about the consequence of making C++ adopt the C rule,
> but I suspect it would break something having to do with templates
> and/or overloading.

I think requiring an explicit cast in C would help avoid errors in code 
- but obviously you want to be careful introducing a feature that would 
break so much existing code.  Equally, you don't want to remove the 
feature from C++ - so this would have to stand as a difference.

>
> The two committees do make some effort to avoid too many
> incompatibilities -- and I'd *like* to see C++ adopt a few more
> C99 and C11 features than it has so far.
>

Me too.

I'd also like to see the committees working together when they are doing 
the same thing.  It is just silly that C11 has "_Static_assert" while 
C++11 has "static_assert".

0
david2384 (2168)
8/26/2012 9:38:47 PM
Am 26.08.2012 23:19, schrieb Keith Thompson:
> The two committees do make some effort to avoid too many
> incompatibilities

definitively

> -- and I'd *like* to see C++ adopt a few more
> C99 and C11 features than it has so far.

on my wish list would be

- variably modified types (not necessarily VLA but pointers to VLA are
  nice)
- restrict
- designated initializers
- compound literals
- type punning through unions
- compatible complex types

the other way round there would probably also be some things from C++
that would be worth considering in C. Simple things such as {} for
default initializers, a larger concept of compile time constants, the
same possibilities for declarations inside control structures (static
objects, and extend the concept to "if" and "while", not only
"for"). But I probably don't know enough of modern C++ to completely
appreciate what this could offer to C.

Then the two could come together to enforce some revolutionary new
things like fixing signed integer representations to two's complement,
disallowing padding bits for integral types, disallowing trap
representations, force definition of [u]intptr_t and other crude stuff
like that.

Jens
0
8/26/2012 9:41:56 PM
Am 26.08.2012 23:38, schrieb David Brown:
> I'd also like to see the committees working together when they are doing
> the same thing.  It is just silly that C11 has "_Static_assert" while
> C++11 has "static_assert".

They are working successfully working together, here. C has
"static_assert", too, only that it is a macro defined in a header
file. All new keywords that are introduced to C are first introduced in
form of identifiers that had been reserved before, such that the
introduction doesn't break existing code. If you want to have
"static_assert" or "bool" you'd have to include the corresponding
header, and you'll see immediately where a particular incompatibility
came from.

Jens


0
8/26/2012 9:50:56 PM
> C++ does not.  Making C adopt the C++ rule would break tons
> of existing code (struct foo *ptr = malloc(N * sizeof *ptr)).

Yes.  I recently wrote a little windows utility in C, but had to translate the brains so it could be used as a C++ module.  The C++ void* insanity was biggest problem.

> I'm less sure about the consequence of making C++ adopt the C rule,
> but I suspect it would break something having to do with templates
> 
> and/or overloading.


Yep.  At the end o the day, this kind of incompatibility is only a minor nuisance.  Changing fundamental things in either language would be much worse.  Especially if the change is to C++, because nobody understands how that thing works.

0
8/26/2012 10:05:46 PM
On 8/26/2012 4:57 AM, Ansel wrote:
> Isn't it a lame use of human time and effort to maintain completely separate
> C and C++ standards? As in the words of Betty White about Facebook: "It
> seems like an incredible waste of time". Why don't the two standards groups
> get together and agree on a common specification for the ground which both
> standards cover? There would still be two separate standards, but they'd
> both be exactly the same for the common ground. The common ground document
> could be referred to by both standards instead of being maintained by both
> groups in individual efforts resulting in different verbage in separate
> specifications for the same functionality. This should happen after both
> groups agree to completely align the C subset functionality on the next
> realease of standards (e.g., VLAs? No one using them? Drop 'em in the name
> of cooperation going forward).
>
>

IMHO:
C++ could adopt C99 or C11 as its C subset (and make "void *" support 
implicit conversion to other pointer types, formally allow "#include 
<stdio.h>" and friends, adopt the "((void *)0)" definition of NULL, ...);
and C could discourage use of C++ reserved words as identifiers, or 
maybe even have compilers generate warnings about it ("Foo *this;" -> 
"warning: 'this' is a reserved word in C++", ...).

similarly, when possible/reasonable, APIs could be defined in C-friendly 
ways, such that it is not necessary to have redundant versions of an 
API, so the C API is the canonical one, and the C++ version is mostly 
just syntax sugar (wrapper classes and templates).


or such...

0
cr88192355 (1928)
8/27/2012 2:08:41 AM
On Sunday, August 26, 2012 9:57:30 AM UTC, Ansel wrote:
> Isn't it a lame use of human time and effort to maintain completely separate 
> 
> C and C++ standards? As in the words of Betty White about Facebook: "It 
> 

C isn't subset of C++.
C++ isn't superset of C.
They are different.
C++ is a new language.

Now I somewhat agree with a similar opinion thrown long time ago:

  C++ has no relationship with C except its name stolen from C
0
8/27/2012 2:49:32 AM
David Brown wrote:
> On 26/08/2012 23:19, Keith Thompson wrote:
>> David Brown <david@westcontrol.removethisbit.com> writes:

>> I'm less sure about the consequence of making C++ adopt the C rule,
>> but I suspect it would break something having to do with templates
>> and/or overloading.
>
> I think requiring an explicit cast in C would help avoid errors in
> code - but obviously you want to be careful introducing a feature
> that would break so much existing code.  Equally, you don't want to
> remove the feature from C++ - so this would have to stand as a
> difference.

Well, there is "standard" and "de facto standard". Once embarked upon the 
path toward greater compatibility, one need not stop at the ISO level. 
Beyond that, there is the implementation (vendor) level, and it appears (to 
me) that a few "de facto standard" compiler switches might be the solution 
to issues where C and C++ cannot "get it together". Of course, that is not 
to be used as a crutch for not making some "painful" changes, but it is 
another dimension of the project. That said, there is nothing stopping some 
compiler vendor(s) from bypassing all the formalities and "just doing it!" 
that way and letting users decide. It may even be the best way to go about 
it, for it could "happen overnight" instead of next year.

Compiler switches: ye or nay?
Vendor-driven approach: ye or nay? 


0
tinker454 (114)
8/27/2012 3:25:46 AM
Keith Thompson wrote:
> Johannes Bauer <dfnsonfsduifb@gmx.de> writes:
>> On 26.08.2012 11:57, Ansel wrote:
>>> This should happen after both
>>> groups agree to completely align the C subset functionality on the
>>> next realease of standards (e.g., VLAs? No one using them? Drop 'em
>>> in the name of cooperation going forward).
>>
>> Ever heared of printf?
>
> You mean the standard C++ function declared in <cstdio>?
> Yes, I've heard of it; why do you ask?

(I was "afraid" of asking. I thought he was on the warpath, and I didn't get 
what he was after either.) 


0
tinker454 (114)
8/27/2012 3:33:30 AM
lovecreatesbeauty wrote:
> On Sunday, August 26, 2012 9:57:30 AM UTC, Ansel wrote:
>> Isn't it a lame use of human time and effort to maintain completely
>> separate
>>
>> C and C++ standards? As in the words of Betty White about Facebook:
>> "It
>>
>
> C isn't subset of C++.
> C++ isn't superset of C.

The thought behind the OP was, though, "*could* it be so, and to good 
effect?".

> They are different.
> C++ is a new language.
>
> Now I somewhat agree with a similar opinion thrown long time ago:
>
>  C++ has no relationship with C except its name stolen from C 


0
tinker454 (114)
8/27/2012 3:40:46 AM
lovecreatesbeauty <lovecreatesbeauty@gmail.com> writes:
> On Sunday, August 26, 2012 9:57:30 AM UTC, Ansel wrote:
>> Isn't it a lame use of human time and effort to maintain completely
>> separate
>> 
>> C and C++ standards? As in the words of Betty White about Facebook:
>> "It
>
> C isn't subset of C++.
> C++ isn't superset of C.
> They are different.
> C++ is a new language.

True (but I'd say "newer" rather than "new").

> Now I somewhat agree with a similar opinion thrown long time ago:
>
>   C++ has no relationship with C except its name stolen from C

I completely disagree with that.  C++ is clearly derived from C.
It's *nearly* a superset of C.  Almost the entire standard C library
is included in C by reference.  The C and C++ committees coordinate
with each other to avoid unnecessary incompatibilities.

It's not difficult (though sometimes a bit tricky) to write
substantial programs that are valid C and valid C++ with the same
semantics.  Try that with two languages that have "no relationship"
(say, C and Fortran).

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
8/27/2012 4:01:33 AM
On Monday, August 27, 2012 6:26:19 AM UTC+3, Ansel wrote:
> David Brown wrote:
> > On 26/08/2012 23:19, Keith Thompson wrote:
> >> I'm less sure about the consequence of making C++ adopt the C rule,
> >> but I suspect it would break something having to do with templates
> >> and/or overloading.
> >
> > I think requiring an explicit cast in C would help avoid errors in
> > code - but obviously you want to be careful introducing a feature
> > that would break so much existing code.  Equally, you don't want to
> > remove the feature from C++ - so this would have to stand as a
> > difference.
> 
> Well, there is "standard" and "de facto standard". Once embarked upon the 
> path toward greater compatibility, one need not stop at the ISO level. 
> Beyond that, there is the implementation (vendor) level, and it appears (to 
> me) that a few "de facto standard" compiler switches might be the solution 
> to issues where C and C++ cannot "get it together". Of course, that is not 
> to be used as a crutch for not making some "painful" changes, but it is 
> another dimension of the project. That said, there is nothing stopping some 
> compiler vendor(s) from bypassing all the formalities and "just doing it!" 
> that way and letting users decide. It may even be the best way to go about 
> it, for it could "happen overnight" instead of next year.

That is wishful thinking. In reality there are vendors like Microsoft
that do not implement something from C99 for decades, nothing to talk
of accepting it 'as extension' by C++ compiler as well.

Why is that? Because the vendors compete with each other. They do not
want the code written for their platform to compile and run on other
platform. They even detect the competing platform and run worse there
like is case with ICC.

Open source solves it only slightly. There are always related
operating system or platform vendors who participate or pay to
squeeze their 'extension' into compiler. If they can not agree about
fair play behind board of standards then there is snowball's chance
in hell that it happens outside.
0
ootiib (965)
8/27/2012 4:46:49 AM
On 2012-08-26, Varun Tewari <tewari.varun@gmail.com> wrote:
> As long as libraries like POSIX etc are willing to migrate, I vouch for single standard to cover both, ++ anyway is superset of C.

That isn't true.  It IS true that code can be written that is
acceptable to either relatively easy, but a true superset it isn't:

    int *number = malloc(sizeof(int));

is perfectly valid C but needs an explicit typecast in the "superset".

-- 
Andrew Smallshaw
andrews@sdf.lonestar.org
0
andrews (362)
8/27/2012 6:29:48 AM
On 26/08/2012 23:50, Jens Gustedt wrote:
> Am 26.08.2012 23:38, schrieb David Brown:
>> I'd also like to see the committees working together when they are doing
>> the same thing.  It is just silly that C11 has "_Static_assert" while
>> C++11 has "static_assert".
>
> They are working successfully working together, here. C has
> "static_assert", too, only that it is a macro defined in a header
> file. All new keywords that are introduced to C are first introduced in
> form of identifiers that had been reserved before, such that the
> introduction doesn't break existing code. If you want to have
> "static_assert" or "bool" you'd have to include the corresponding
> header, and you'll see immediately where a particular incompatibility
> came from.
>

I understand this (and in fact knew it was the case).  But that doesn't 
stop it being silly!

The C committee should learn - as the C++ committee apparently knows - 
that backwards compatibility is only "important", not "critical".  It is 
/okay/ to introduce a new "static_assert" keyword in the new version of 
a language, as long as people can continue to use their compilers with 
older standards.  This is not a new idea - consider K&R style function 
declarations, for example.

Failing that, what is to stop the C++ people following the C people here?

Anyway, this is just one example that is easy to see, where the two 
committees added the same feature to the two languages but with 
differing details.

The more annoying issue, as I see it, is the increasing gap of C 
features that are missing in C++.  There are steadily more features 
being added to C for embedded use, such as fixed point formats.  But C++ 
doesn't get that sort of thing, because it could all be implemented in a 
class.  I understand the principle that you should not add something to 
the core library if it can be done just as well in a class - but the C++ 
committee doesn't seem to realise that compatibility with C is important 
here.


0
david2384 (2168)
8/27/2012 7:43:10 AM
On 26/08/2012 23:41, Jens Gustedt wrote:
> Am 26.08.2012 23:19, schrieb Keith Thompson:
>> The two committees do make some effort to avoid too many
>> incompatibilities
>
> definitively
>
>> -- and I'd *like* to see C++ adopt a few more
>> C99 and C11 features than it has so far.
>
> on my wish list would be
>
> - variably modified types (not necessarily VLA but pointers to VLA are
>    nice)
> - restrict
> - designated initializers
> - compound literals
> - type punning through unions
> - compatible complex types
>

I'd add fixed point types to that list - as well as a proper way to 
define exact sized fixed point types (sort of like "stdint.h").

> the other way round there would probably also be some things from C++
> that would be worth considering in C. Simple things such as {} for
> default initializers, a larger concept of compile time constants, the
> same possibilities for declarations inside control structures (static
> objects, and extend the concept to "if" and "while", not only
> "for"). But I probably don't know enough of modern C++ to completely
> appreciate what this could offer to C.
>
> Then the two could come together to enforce some revolutionary new
> things like fixing signed integer representations to two's complement,
> disallowing padding bits for integral types, disallowing trap
> representations, force definition of [u]intptr_t and other crude stuff
> like that.
>

If someone is making a wish list here, I'd add support for defining 
endianness (allowing code to explicitly define and use variables and 
types as big endian or little endian independently of the architecture) 
and bit field ordering.  That would be great for portable code.

Support for types bigger than "char" which are "can always alias" would 
be a big help whenever you need to move data around, and an 8-bit type 
that does not alias would be nice for small systems.

Proper, standardised memory barriers of different types and granularity 
would be a help for some low-level programming.

Generally speaking, it would be nice to be able to do more C++ in 
low-level and embedded code, and cut out some more of the last remnants 
of assembly that is still needed.

> Jens
>

0
david2384 (2168)
8/27/2012 8:40:36 AM
On Aug 26, 11:28=A0am, Johannes Bauer <dfnsonfsdu...@gmx.de> wrote:
> On 26.08.2012 11:57, Ansel wrote:
>
> > This should happen after both
> > groups agree to completely align the C subset functionality on the next
> > realease of standards (e.g., VLAs? No one using them? Drop 'em in the n=
ame
> > of cooperation going forward).
>
> Ever heared of printf?

yes, why? Does it use VLAs?
0
8/27/2012 8:44:48 AM
On Aug 27, 3:49=A0am, lovecreatesbeauty <lovecreatesbea...@gmail.com>
wrote:
> On Sunday, August 26, 2012 9:57:30 AM UTC, Ansel wrote:
> > Isn't it a lame use of human time and effort to maintain completely sep=
arate
>
> > C and C++ standards? As in the words of Betty White about Facebook: "It
>
> C isn't subset of C++.
> C++ isn't superset of C.
> They are different.
> C++ is a new language.
>
> Now I somewhat agree with a similar opinion thrown long time ago:
>
> =A0 C++ has no relationship with C except its name stolen from C

which is plainly nonsense
0
8/27/2012 8:56:33 AM

lovecreatesbeauty wrote:
> On Sunday, August 26, 2012 9:57:30 AM UTC, Ansel wrote:
> > Isn't it a lame use of human time and effort to maintain completely separate
> >
> > C and C++ standards? As in the words of Betty White about Facebook: "It
> >
>
> C isn't subset of C++.
> C++ isn't superset of C.
> They are different.
> C++ is a new language.
>
> Now I somewhat agree with a similar opinion thrown long time ago:
>
>   C++ has no relationship with C except its name stolen from C

Pure rubbish here, out of what was C with classes born....?
0
divadsmall (21)
8/27/2012 11:37:31 AM
On 08/26/2012 10:49 PM, lovecreatesbeauty wrote:
....
> Now I somewhat agree with a similar opinion thrown long time ago:
> 
>   C++ has no relationship with C except its name stolen from C

Nonsense. Almost every feature of C90 is a feature of C++98, and many of
the features added to C99 have since become part of later versions of
C++. C++ has a large number of additional features, and modifies the
meaning of some constructs that are permitted by both languages, but
it's not difficult to write code that avoids all of the
incompatibilities. It is very difficult to write strictly conforming C
that cannot be converted into C code that compiles without change of
meaning as C++ code.

In fact, many people who claim that they have C++ experience have in
fact only used C++ to compile code that would (with at most minor
modifications) compile with exactly the same meaning as C code. This can
actually be a problem if you're trying to hire someone to work on code
that makes extensive use of the features C++ has that C doesn't.
-- 
James Kuyper
0
jameskuyper (5635)
8/27/2012 12:50:57 PM
Am 27.08.2012 09:43, schrieb David Brown:
> On 26/08/2012 23:50, Jens Gustedt wrote:
>> Am 26.08.2012 23:38, schrieb David Brown:
>>> I'd also like to see the committees working together when they are doing
>>> the same thing.  It is just silly that C11 has "_Static_assert" while
>>> C++11 has "static_assert".
>>
>> They are working successfully working together, here. C has
>> "static_assert", too, only that it is a macro defined in a header
>> file. All new keywords that are introduced to C are first introduced in
>> form of identifiers that had been reserved before, such that the
>> introduction doesn't break existing code. If you want to have
>> "static_assert" or "bool" you'd have to include the corresponding
>> header, and you'll see immediately where a particular incompatibility
>> came from.
>>
> 
> I understand this (and in fact knew it was the case).  But that doesn't
> stop it being silly!
> 
> The C committee should learn - as the C++ committee apparently knows -
> that backwards compatibility is only "important", not "critical".  It is
> /okay/ to introduce a new "static_assert" keyword in the new version of
> a language, as long as people can continue to use their compilers with
> older standards.  This is not a new idea - consider K&R style function
> declarations, for example.

This is your opinion and the C committee seem to have a different
one. Calling it silly is not very constructive, in any case it is not
going to change soon, I guess.

Important fact is that for these features code will equally well
compile in both frameworks.

> Failing that, what is to stop the C++ people following the C people here?
> 
> Anyway, this is just one example that is easy to see, where the two
> committees added the same feature to the two languages but with
> differing details.
> 
> The more annoying issue, as I see it, is the increasing gap of C
> features that are missing in C++.  There are steadily more features
> being added to C for embedded use, such as fixed point formats.  But C++
> doesn't get that sort of thing, because it could all be implemented in a
> class.  I understand the principle that you should not add something to
> the core library if it can be done just as well in a class - but the C++
> committee doesn't seem to realise that compatibility with C is important
> here.

I completely agree on that point, and BTW there are equal points in
the other direction from C++ to C.

Best example for something completely trivial is "{}" as a default
initializer. What the hell does C gain by imposing that there is at
least a 0 in it � la "{0}" ?

Or that C adopted declarations in "for" loops but doesn't allow
"static" declarations or "enum" declarations, and doesn't allow
declarations in "if" or "while" ?

These things look just as if somebody was voluntarily seeking to
introduce incompatibilities, instead of reducing them.

Jens
0
8/27/2012 4:24:46 PM
Am 27.08.2012 10:40, schrieb David Brown:
> If someone is making a wish list here, I'd add support for defining
> endianness (allowing code to explicitly define and use variables and
> types as big endian or little endian independently of the architecture)


> and bit field ordering.

I think this is more strictly defined for C already than for C++,
perhaps the definition that C has would be sufficient for your needs?

> That would be great for portable code.
> 
> Support for types bigger than "char" which are "can always alias" would
> be a big help whenever you need to move data around, and an 8-bit type
> that does not alias would be nice for small systems.

I am not sure that I understand this one. C has the optional uintXX_t
that are guaranteed to have a fixed width no padding etc, if they
exist. Would it for your purpose just suffice to make some of these
types mandatory e.g for 8, 16, 32 and 64 bit integers?

> Proper, standardised memory barriers of different types and granularity
> would be a help for some low-level programming.

My understanding is that these are included in C11 atomics, and since
this part basically identical to C++11, it should be there, too.

> Generally speaking, it would be nice to be able to do more C++ in
> low-level and embedded code, and cut out some more of the last remnants
> of assembly that is still needed.

The atomics extension (optional in C11) should already do a lot in
that direction.

Jens
0
8/27/2012 4:34:38 PM
On 8/26/2012 1:03 PM, Barry Schwarz wrote:
> On Sun, 26 Aug 2012 03:57:30 -0600, "Ansel"
> <tinker454@trytospammenowloser.com> wrote:
>
>> Isn't it a lame use of human time and effort to maintain completely separate
>> C and C++ standards? As in the words of Betty White about Facebook: "It
[...]
> What is your recommended compromise for malloc?
>
>       Should C++ give up its strict type checking and no longer require
> a cast of the return value?
>
> or
>
>       Should C now require the cast and break more than 20 years of
> existing code?

While the former has zero effect on existing C++ code, the latter 
invalidates a huge amount of existing C code.  Obviously, the only "right" 
answer is "A".  Good luck on getting C++ advocates to agree to it, however.

There's also "little" things such as new reserved keywords in C++.  What 
changes to C++ would be required to allow "int new,old;"?

It seems to me that just about anything you could come up with would be 
"change C++ to allow this valid C construct, while not invalidating current 
C++, so that C++ is truly a superset of C".  (Just about anything else would 
mean invalidating existing legal C code.)

It would probably take more time to resolve all of those issues than all of 
the "duplicate effort" currently required for two separate standards.

Basically, "it ain't gonna happen".

-- 
Kenneth Brody
0
kenbrody (1879)
8/27/2012 6:00:02 PM
On 8/26/2012 1:54 PM, jacob navia wrote:
> Le 26/08/12 11:57, Ansel a �crit :
>> Isn't it a lame use of human time and effort to maintain completely separate
>> C and C++ standards? As in the words of Betty White about Facebook: "It
[...]
>
> sizeof('b') is sizeof(int) int C, 1 in C++
>
> Which one would you compromise on?
>
> You do not know what you are talking about dude...

Simple.  Require sizeof(int)==1.  Problem solved.  :-)

-- 
Kenneth Brody
0
kenbrody (1879)
8/27/2012 6:01:03 PM
On 8/27/2012 1:01 PM, Kenneth Brody wrote:
> On 8/26/2012 1:54 PM, jacob navia wrote:
>> Le 26/08/12 11:57, Ansel a �crit :
>>> Isn't it a lame use of human time and effort to maintain completely
>>> separate
>>> C and C++ standards? As in the words of Betty White about Facebook: "It
> [...]
>>
>> sizeof('b') is sizeof(int) int C, 1 in C++
>>
>> Which one would you compromise on?
>>
>> You do not know what you are talking about dude...
>
> Simple.  Require sizeof(int)==1.  Problem solved.  :-)
>

wouldn't work out well or make much sense on most common architectures.

better would probably be: pick one way or the other.

0
cr88192355 (1928)
8/27/2012 7:29:13 PM
Jens Gustedt <jens.gustedt@loria.fr> wrote:
> 
> on my wish list would be
> 
> - variably modified types (not necessarily VLA but pointers to VLA are
>   nice)

What good are pointers to VLAs without VLAs?  What would they point
to???
-- 
Larry Jones

I'm so disappointed. -- Calvin
0
8/27/2012 8:50:39 PM
Am 27.08.2012 22:50, schrieb lawrence.jones@siemens.com:
> Jens Gustedt <jens.gustedt@loria.fr> wrote:
>>
>> on my wish list would be
>>
>> - variably modified types (not necessarily VLA but pointers to VLA are
>>   nice)
> 
> What good are pointers to VLAs without VLAs?  What would they point
> to???
> 

There is a simple idiom to deal with large matrices

double (*A)[m][n] = malloc *A;

You can easily handle such matrices with functions

void product(size_t n, size_t m, size_t k, double (*A)[n][k], double
(*B)[k][n], double (*C)[n][m]);

All those *A, *B, *C carry all there sizes with them so you can access
elements as (*A)[i][j] etc

If you allocate all those matrices with malloc as above, no danger of
stack overflow.

Admittedly the (*A) notation is not the most comfortable, but works.
C++'s references would be the perfect complement for that and would make
that idiom really useful.

Jens

http://gustedt.wordpress.com/2011/01/09/dont-be-afraid-of-variably-modified-types/

0
8/27/2012 10:27:29 PM
lawrence.jones@siemens.com writes:
> Jens Gustedt <jens.gustedt@loria.fr> wrote:
>> on my wish list would be
>> 
>> - variably modified types (not necessarily VLA but pointers to VLA are
>>   nice)
>
> What good are pointers to VLAs without VLAs?  What would they point
> to???

I suppose you could permit VLAs with allocated storage duration
but not with automatic storage duration.  (They're already not
permitted to have static storage duration.)  That would remove the
case where you can define a VLA, but there's no way to handle an
allocation failure.  It would also remove the case where they're
most convenient.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
8/27/2012 11:15:50 PM
On 2012-08-26 21:08, BGB wrote:
> IMHO:
> C++ could adopt C99 or C11 as its C subset (and make "void *" support
> implicit conversion to other pointer types, formally allow "#include
> <stdio.h>" and friends, adopt the "((void *)0)" definition of NULL, ...);

C++ _does_ formally allow "include <stdio.h>". <XXX.h> defines the same 
set of entities as <cXXX>, except that <cXXX> provides them in namespace 
std (and optionally the global namespace), whereas <XXX.h> provides them 
in the global namespace (and optionally in namespace std). See 17.6.1.2 
and Appendix D.5 in C++11.

Definition of NULL as ((void*)0) is contingent on the implicit 
conversion of void* to other pointer types.

That implicit conversion from void* to any pointer type is a dangerous 
hole in the type system. I admit I'm not much of a C programmer anymore: 
the only valid reason I can think of to have this conversion is so that 
malloc calls don't require you to specify the type _three_ times (e.g., 
int* p = (int*)malloc(sizeof(*p)); ).

If I really wanted to pitch the committees for stronger ties between C 
and C++, I'd probably suggest that (a) C pick up nullptr (and nullptr_t) 
to serve as generic null pointer constant, (b) C drop the implicit 
conversion from void*, and (c) both languages use a new distinct type 
that can implicitly convert to any pointer type. Holes in the type 
system are very useful at the fringes of C/C++ programs, I think that 
having distinct "source" (X -> any*) and "sink" (any* -> X) pointer 
types preserves the utility of C-style void* while minimizing the danger.
0
Casey5152 (6)
8/28/2012 2:47:23 AM
On 8/27/2012 9:47 PM, Casey Carter wrote:
> On 2012-08-26 21:08, BGB wrote:
>> IMHO:
>> C++ could adopt C99 or C11 as its C subset (and make "void *" support
>> implicit conversion to other pointer types, formally allow "#include
>> <stdio.h>" and friends, adopt the "((void *)0)" definition of NULL, ...);
>
> C++ _does_ formally allow "include <stdio.h>". <XXX.h> defines the same
> set of entities as <cXXX>, except that <cXXX> provides them in namespace
> std (and optionally the global namespace), whereas <XXX.h> provides them
> in the global namespace (and optionally in namespace std). See 17.6.1.2
> and Appendix D.5 in C++11.
>

fair enough, I had thought it was more like, "cwhatever" was the 
"standard" way in C++ land, and "whatever.h" was "just something that 
happens to work".

admittedly, I have not really dug much into the C++ standard (I have 
looked considerably more into the C standard here).



> Definition of NULL as ((void*)0) is contingent on the implicit
> conversion of void* to other pointer types.
>

well, yes, but I listed that they could add this as well.
probably most C++ code wouldn't notice the change.

possibly, the change could be limited to 'extern "C"' code or similar 
(and/or could be ignored in cases of templates or overloading, or at 
least be a lower priority than any other matches).


> That implicit conversion from void* to any pointer type is a dangerous
> hole in the type system. I admit I'm not much of a C programmer anymore:
> the only valid reason I can think of to have this conversion is so that
> malloc calls don't require you to specify the type _three_ times (e.g.,
> int* p = (int*)malloc(sizeof(*p)); ).
>

there are plenty of uses besides malloc, so malloc is just one of many 
cases (mmap, memcpy, VirtualAlloc, ...).

or, a biggie:
for any user-defined code which accepts or returns "void *".

for example, to do similar tasks in C++ often requires a larger number 
of casts.


> If I really wanted to pitch the committees for stronger ties between C
> and C++, I'd probably suggest that (a) C pick up nullptr (and nullptr_t)
> to serve as generic null pointer constant,

could work...


> (b) C drop the implicit
> conversion from void*,

this would break large amounts of C code.

I don't think people on either side would want changes which cause their 
existing programs to break and have to be rewritten.


> and (c) both languages use a new distinct type
> that can implicitly convert to any pointer type.

we call this 'void *', where this is nearly the only thing that can 
really be done with this type anyways ("void" variables are otherwise 
pretty much useless, ...).


 > Holes in the type
> system are very useful at the fringes of C/C++ programs, I think that
> having distinct "source" (X -> any*) and "sink" (any* -> X) pointer
> types preserves the utility of C-style void* while minimizing the danger.

yes, but the least impact route would be to just pick up C's "void *" 
semantics for this, since C++ code isn't likely to notice, and existing 
C code can keep working unmodified.


0
cr88192355 (1928)
8/28/2012 3:34:35 AM
Am 28.08.2012 01:15, schrieb Keith Thompson:
> lawrence.jones@siemens.com writes:
>> What good are pointers to VLAs without VLAs?  What would they point
>> to???
> 
> I suppose you could permit VLAs with allocated storage duration
> but not with automatic storage duration.  (They're already not
> permitted to have static storage duration.)  That would remove the
> case where you can define a VLA, but there's no way to handle an
> allocation failure.  It would also remove the case where they're
> most convenient.

I just don't agree on the last phrase. Pointers to VLA are very
convenient in function interfaces.

Jens

http://gustedt.wordpress.com/2011/01/09/dont-be-afraid-of-variably-modified-types/

0
8/28/2012 7:20:27 AM
Am 28.08.2012 05:34, schrieb BGB:
> On 8/27/2012 9:47 PM, Casey Carter wrote:
>> and (c) both languages use a new distinct type
>> that can implicitly convert to any pointer type.
> 
> we call this 'void *', where this is nearly the only thing that can
> really be done with this type anyways ("void" variables are otherwise
> pretty much useless, ...).

yes!

That said, I don't really see the point of "void*" as it is in C++
nowadays. Since you'd have to do an explicit conversion any time you
use it, in C++ it has nothing that couldn't be done with a "unsigned
char*". In the contrary, "unsigned char*" allows byte based pointer
arithmetic and to inspect the contents on a byte base.

The only reason, I think, for "void*" is interface compability to
C. Somehow it misses the whole point of it.

Jens
0
8/28/2012 7:27:54 AM
On 27/08/2012 18:24, Jens Gustedt wrote:
> Am 27.08.2012 09:43, schrieb David Brown:
>> On 26/08/2012 23:50, Jens Gustedt wrote:
>>> Am 26.08.2012 23:38, schrieb David Brown:
>>>> I'd also like to see the committees working together when they are doing
>>>> the same thing.  It is just silly that C11 has "_Static_assert" while
>>>> C++11 has "static_assert".
>>>
>>> They are working successfully working together, here. C has
>>> "static_assert", too, only that it is a macro defined in a header
>>> file. All new keywords that are introduced to C are first introduced in
>>> form of identifiers that had been reserved before, such that the
>>> introduction doesn't break existing code. If you want to have
>>> "static_assert" or "bool" you'd have to include the corresponding
>>> header, and you'll see immediately where a particular incompatibility
>>> came from.
>>>
>>
>> I understand this (and in fact knew it was the case).  But that doesn't
>> stop it being silly!
>>
>> The C committee should learn - as the C++ committee apparently knows -
>> that backwards compatibility is only "important", not "critical".  It is
>> /okay/ to introduce a new "static_assert" keyword in the new version of
>> a language, as long as people can continue to use their compilers with
>> older standards.  This is not a new idea - consider K&R style function
>> declarations, for example.
>
> This is your opinion and the C committee seem to have a different
> one. Calling it silly is not very constructive, in any case it is not
> going to change soon, I guess.
>

Yes, I know the committees have a different opinion.  And like all 
committees, some of their decisions are based on good ideas, lots of 
thought, and lots of experience - and others are based on opinions, 
stubbornness and bad compromises.  It is never possible to make everyone 
happy about everything.

And while the "static_assert" example is a minor one, especially (as you 
mention) there is a reasonable workaround (using a standard include 
file), it does stand out as a clear example of each committee being 
determined to do things /their/ way rather than working together on what 
should be common ground.

> Important fact is that for these features code will equally well
> compile in both frameworks.
>
>> Failing that, what is to stop the C++ people following the C people here?
>>
>> Anyway, this is just one example that is easy to see, where the two
>> committees added the same feature to the two languages but with
>> differing details.
>>
>> The more annoying issue, as I see it, is the increasing gap of C
>> features that are missing in C++.  There are steadily more features
>> being added to C for embedded use, such as fixed point formats.  But C++
>> doesn't get that sort of thing, because it could all be implemented in a
>> class.  I understand the principle that you should not add something to
>> the core library if it can be done just as well in a class - but the C++
>> committee doesn't seem to realise that compatibility with C is important
>> here.
>
> I completely agree on that point, and BTW there are equal points in
> the other direction from C++ to C.
>
> Best example for something completely trivial is "{}" as a default
> initializer. What the hell does C gain by imposing that there is at
> least a 0 in it � la "{0}" ?

Agreed.

>
> Or that C adopted declarations in "for" loops but doesn't allow
> "static" declarations or "enum" declarations, and doesn't allow
> declarations in "if" or "while" ?
>

I don't think I would view a declaration within an "if" as good style 
myself, but I can imagine when people would want to use it - and it 
would make sense for consistency.

> These things look just as if somebody was voluntarily seeking to
> introduce incompatibilities, instead of reducing them.
>

I think that was roughly the point I was trying to make.

Basically, I just want to be able to mix and match C and C++ code 
freely.  I want to be able to write in the same style in each language. 
  If I am not using C++ features, I want the code to be compilable as C 
or C++, with the same functionality each time.  And I want to be able to 
do so without artificially restricting the features I can use in C. 
It's okay if I have to #include a few standard headers, and put in a few 
extern "C" wrappers.

Am I really asking too much?


(Here's another thing C should support - it should accept extern "C".)

> Jens
>

0
david2384 (2168)
8/28/2012 8:21:36 AM
Am 28.08.2012 10:21, schrieb David Brown:
> Basically, I just want to be able to mix and match C and C++ code
> freely.  I want to be able to write in the same style in each language.
>  If I am not using C++ features, I want the code to be compilable as C
> or C++, with the same functionality each time.  And I want to be able to
> do so without artificially restricting the features I can use in C. It's
> okay if I have to #include a few standard headers, and put in a few
> extern "C" wrappers.
> 
> Am I really asking too much?

personnaly, I don't think so, but seen in the historical context, most
likely.

> (Here's another thing C should support - it should accept extern "C".)

Ah, yes, a good one.

Sometime the next days, if and when I find the time, I'll probably
start to compile a list of these things. Or better three list

 - C features missing in C++
 - C++ features missing in C
 - points where both should (and could) move to meet on a common
   ground

I already have a list of defects and feature requests for C. That
would perfectly fit, there.

Jens


0
8/28/2012 8:57:06 AM
On 27/08/2012 18:34, Jens Gustedt wrote:
> Am 27.08.2012 10:40, schrieb David Brown:
>> If someone is making a wish list here, I'd add support for defining
>> endianness (allowing code to explicitly define and use variables and
>> types as big endian or little endian independently of the architecture)
>
>
>> and bit field ordering.
>
> I think this is more strictly defined for C already than for C++,
> perhaps the definition that C has would be sufficient for your needs?
>

No, it is not defined nearly well enough.

There are ambiguities regarding padding, alignment, etc., especially as 
the size of the fields change.  Different underlying types of the fields 
can make a difference (especially if you want something like an enum 
type), and compiler flags often affect the structure.  The biggest 
failing is that there is no way to relate the order to the underlying 
bits - the first field could be the least significant bit on one 
architecture, and the most significant bit on another architecture (or 
even different compilers on the same target).

Bitfields /can/ be a very convenient way to pack data, but are only 
really safe if the data stays within the same program.  You have to mess 
around with a lot of #ifdef's and alternative definitions to get 
something portable (you can see this sort of mess in the Linux source 
code for filesystems, for example).

Some clear and unambiguous method of fixing this would be very useful - 
something like "__attribute__((packed, lsbfirst))", using gcc attribute 
syntax.

>> That would be great for portable code.
>>
>> Support for types bigger than "char" which are "can always alias" would
>> be a big help whenever you need to move data around, and an 8-bit type
>> that does not alias would be nice for small systems.
>
> I am not sure that I understand this one. C has the optional uintXX_t
> that are guaranteed to have a fixed width no padding etc, if they
> exist. Would it for your purpose just suffice to make some of these
> types mandatory e.g for 8, 16, 32 and 64 bit integers?

No, these types are fine (I use them all the time).  The issue is with 
aliasing.

Sometimes in programming, you need to move data around in a format other 
than the data's "natural" format.  Maybe you've got data held in a 
struct, and you want to make a copy of the whole struct.  Or maybe you 
want to pass data around using the Modbus protocol, which likes to treat 
everything using 16-bit words.  The trouble comes when you want to work 
with a pointer to the struct data using a *uint16_t pointer (or any 
other "incompatible" pointer).  The compiler knows that the struct is 
incompatible with a uint16_t, so the pointer cannot point to the struct, 
and therefore nothing read or written to the struct can affect anything 
read or written through the pointer.

Chars, or pointers to char, have the opposite problem - because they can 
alias anything, the compiler has to assume that any access through a 
char pointer can hit any other data (well, not /any/ other data - local 
data in registers is safe).  This can lead to lost optimisation 
opportunities.

So I would like to see types other than inefficient 8-bit types that 
have the "alias everything" property, and 8-bit types that don't alias 
anything.

An alternative is to be able to specify aliasing more conveniently, 
without having to use type-punning unions.

>
>> Proper, standardised memory barriers of different types and granularity
>> would be a help for some low-level programming.
>
> My understanding is that these are included in C11 atomics, and since
> this part basically identical to C++11, it should be there, too.

Well, atomics helps a bit - but they are overkill.  Mostly all you need 
is to be able to say "make sure the store to variable X is completed 
here", or "don't move the read before this point".  You can get a fair 
amount of this using volatile accesses, but sometimes it is much more 
convenient with general barriers.  Depending on the target cpu, you may 
also want the barriers to issue additional instructions to flush buffers.

>
>> Generally speaking, it would be nice to be able to do more C++ in
>> low-level and embedded code, and cut out some more of the last remnants
>> of assembly that is still needed.
>
> The atomics extension (optional in C11) should already do a lot in
> that direction.
>
> Jens
>

0
david2384 (2168)
8/28/2012 10:40:00 AM
=D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=A9=D7=9C=D7=99=
=D7=A9=D7=99, 28 =D7=91=D7=90=D7=95=D7=92=D7=95=D7=A1=D7=98 2012 08:27:55 U=
TC+1, =D7=9E=D7=90=D7=AA Jens Gustedt:
> Am 28.08.2012 05:34, schrieb BGB:
>=20
>=20
> That said, I don't really see the point of "void*" as it is in C++
> nowadays. Since you'd have to do an explicit conversion any time you
> use it, in C++ it has nothing that couldn't be done with a "unsigned
> char*". In the contrary, "unsigned char*" allows byte based pointer
> arithmetic and to inspect the contents on a byte base.
>=20
void * just documents that "this is an unsigned char * holding arbitrary=20
bytes". It's a bit pointless to require a cast to and from, because you
can't use the data in any way without converting it to something else,=20
but that's just a minor syntactical niggle.
0
8/28/2012 11:04:07 AM
Am 28.08.2012 12:40, schrieb David Brown:
> On 27/08/2012 18:34, Jens Gustedt wrote:
>> Am 27.08.2012 10:40, schrieb David Brown:
>>> If someone is making a wish list here, I'd add support for defining
>>> endianness (allowing code to explicitly define and use variables and
>>> types as big endian or little endian independently of the architecture)
>>
>>
>>> and bit field ordering.
>>
>> I think this is more strictly defined for C already than for C++,
>> perhaps the definition that C has would be sufficient for your needs?
>>
> 
> No, it is not defined nearly well enough.
> 
> There are ambiguities regarding padding, alignment, etc., especially as
> the size of the fields change.  Different underlying types of the fields
> can make a difference (especially if you want something like an enum
> type),

well C does only allow enums as implementation specific. For C the
only portable types are of signed and unsigned int and _Bool.

And the only real ambiguity that I see is for bit-fields that may
cross storage boundaries, here the standard allows either realize part
of the bitfield in one unit and the other part in the other or to
accumulate them in the second unit. As long as all bits fit, they must
be placed in the same unit, and if you want to force it to move to the
next unit you can place a :0.

>> I am not sure that I understand this one. C has the optional uintXX_t
>> that are guaranteed to have a fixed width no padding etc, if they
>> exist. Would it for your purpose just suffice to make some of these
>> types mandatory e.g for 8, 16, 32 and 64 bit integers?
> 
> No, these types are fine (I use them all the time).  The issue is with
> aliasing.
> 
> Sometimes in programming, you need to move data around in a format other
> than the data's "natural" format.  Maybe you've got data held in a
> struct, and you want to make a copy of the whole struct.  Or maybe you
> want to pass data around using the Modbus protocol, which likes to treat
> everything using 16-bit words.  The trouble comes when you want to work
> with a pointer to the struct data using a *uint16_t pointer (or any
> other "incompatible" pointer).  The compiler knows that the struct is
> incompatible with a uint16_t, so the pointer cannot point to the struct,
> and therefore nothing read or written to the struct can affect anything
> read or written through the pointer.

wouldn't something like

  struct toto _Alignas(uint16_t) t;

  struct toto volatile _Alignas(uint16_t) vt = t;
  uint16_t volatile*words = (uint16_t*)&vt;
  /* do the fiddling that you want */
  t = vt;

do the trick?

But perhaps I am too naive :)

> Chars, or pointers to char, have the opposite problem - because they can
> alias anything, the compiler has to assume that any access through a
> char pointer can hit any other data (well, not /any/ other data - local
> data in registers is safe).  This can lead to lost optimisation
> opportunities.

as long as the char* receives is value in the same spot modern
compilers should be able to avoid most problems, I would guess. But
yes if you have a char* that might point anywhere, it might impact any
of your variables. But such a pointer you usually receive as a
parameter of a function, so you should carefully use "restrict" to
tell the compiler what he may assume. (and oops we are back on track
for the the C - C++ incompabilities :)

I still not sure that I understand what you'd want. One generic data
type for each possible alignment specification?

> So I would like to see types other than inefficient 8-bit types that
> have the "alias everything" property, and 8-bit types that don't alias
> anything.

You mean that any "char*" parameter to a function could ruin some
optimization? Never thought of it like that. But if you have a "char*"
(and not "char const*") then probably it is a good idea to add a
"restrict" where ever you may.

> An alternative is to be able to specify aliasing more conveniently,
> without having to use type-punning unions.

"uintXX_t*" would be good candidates, here.

>>
>>> Proper, standardised memory barriers of different types and granularity
>>> would be a help for some low-level programming.
>>
>> My understanding is that these are included in C11 atomics, and since
>> this part basically identical to C++11, it should be there, too.
> 
> Well, atomics helps a bit - but they are overkill.  Mostly all you need
> is to be able to say "make sure the store to variable X is completed
> here", or "don't move the read before this point".  You can get a fair
> amount of this using volatile accesses, but sometimes it is much more
> convenient with general barriers.  Depending on the target cpu, you may
> also want the barriers to issue additional instructions to flush buffers.

Declaring a variable that you'd want to flush as atomic would
certainly be overkill. But I don't see completely why

atomic_thread_fence

couldn't serve your purpose, at least aproximatively. True, it doesn't
ensure a fence for just one variable, but then again with aliasing
you'd have to make pretty much sure that your memory bus calmed down
before supposing that no other variable is affected by a load or
store. So my idea would be that atomic_thread_fence with a careful
selection of the memory_order that you pass as argument would come
relatively close to what you want.

Jens
0
8/28/2012 12:06:18 PM
On 28/08/2012 14:06, Jens Gustedt wrote:
> Am 28.08.2012 12:40, schrieb David Brown:
>> On 27/08/2012 18:34, Jens Gustedt wrote:
>>> Am 27.08.2012 10:40, schrieb David Brown:
>>>> If someone is making a wish list here, I'd add support for defining
>>>> endianness (allowing code to explicitly define and use variables and
>>>> types as big endian or little endian independently of the architecture)
>>>
>>>
>>>> and bit field ordering.
>>>
>>> I think this is more strictly defined for C already than for C++,
>>> perhaps the definition that C has would be sufficient for your needs?
>>>
>>
>> No, it is not defined nearly well enough.
>>
>> There are ambiguities regarding padding, alignment, etc., especially as
>> the size of the fields change.  Different underlying types of the fields
>> can make a difference (especially if you want something like an enum
>> type),
>
> well C does only allow enums as implementation specific. For C the
> only portable types are of signed and unsigned int and _Bool.
>
> And the only real ambiguity that I see is for bit-fields that may
> cross storage boundaries, here the standard allows either realize part
> of the bitfield in one unit and the other part in the other or to
> accumulate them in the second unit. As long as all bits fit, they must
> be placed in the same unit, and if you want to force it to move to the
> next unit you can place a :0.
>

That's true - but I want to be able to unambiguously place fields across 
boundaries, and I want to be able to use fields of different types in a 
well-defined, portable and cross-platform way.  For example, I want to 
be able to write:

struct {
	uint8_t a;
	uint8_t b;
	uint8_t c : 4;
	uint8_t d : 4;
	uint8_t e;
}

I want to be guaranteed that this struct takes 32 bits, and is aligned 
to 8-bit boundaries.

Most C compilers allow such code, but it is not in the standards.  They 
also (mostly) allow enumerated types, and the size and alignment of the 
field comes from the size of the bitfield rather than the size of the 
underlying enum (which in standard C is a signed or unsigned int, or 
possibly a signed or unsigned long - but compiler options may allow it 
to be smaller).

AFAIK, C++ allows such code in the standards.

However, no standards give any guarantees about alignment and padding. 
And certainly bit ordering is not mentioned.


>>> I am not sure that I understand this one. C has the optional uintXX_t
>>> that are guaranteed to have a fixed width no padding etc, if they
>>> exist. Would it for your purpose just suffice to make some of these
>>> types mandatory e.g for 8, 16, 32 and 64 bit integers?
>>
>> No, these types are fine (I use them all the time).  The issue is with
>> aliasing.
>>
>> Sometimes in programming, you need to move data around in a format other
>> than the data's "natural" format.  Maybe you've got data held in a
>> struct, and you want to make a copy of the whole struct.  Or maybe you
>> want to pass data around using the Modbus protocol, which likes to treat
>> everything using 16-bit words.  The trouble comes when you want to work
>> with a pointer to the struct data using a *uint16_t pointer (or any
>> other "incompatible" pointer).  The compiler knows that the struct is
>> incompatible with a uint16_t, so the pointer cannot point to the struct,
>> and therefore nothing read or written to the struct can affect anything
>> read or written through the pointer.
>
> wouldn't something like
>
>    struct toto _Alignas(uint16_t) t;
>
>    struct toto volatile _Alignas(uint16_t) vt = t;
>    uint16_t volatile*words = (uint16_t*)&vt;
>    /* do the fiddling that you want */
>    t = vt;
>
> do the trick?
>
> But perhaps I am too naive :)

Using volatile accesses will force data to be written, and negate 
aliasing issues - since the compiler must read or write the data exactly 
as the volatile accesses dictate, it can't optimise on the basis of 
non-aliasing types.

However, typically we are talking about lumps of data rather than a 
single item (if not, then pass-by-value is probably going to be more 
efficient than using pointers), so extra copies are to be avoided.

And there is the choice between making the data volatile, and thereby 
making most of the "normal" accesses much less efficient, or making only 
some of the accesses explicitly volatile - and thereby risk missing some 
(or at least making messy code).

Usually a memory barrier or two, along with some volatile accesses, 
gives correct code without too much run-time overhead or messy source 
code.  But I can always wish for something better!

>
>> Chars, or pointers to char, have the opposite problem - because they can
>> alias anything, the compiler has to assume that any access through a
>> char pointer can hit any other data (well, not /any/ other data - local
>> data in registers is safe).  This can lead to lost optimisation
>> opportunities.
>
> as long as the char* receives is value in the same spot modern
> compilers should be able to avoid most problems, I would guess. But
> yes if you have a char* that might point anywhere, it might impact any
> of your variables. But such a pointer you usually receive as a
> parameter of a function, so you should carefully use "restrict" to
> tell the compiler what he may assume. (and oops we are back on track
> for the the C - C++ incompabilities :)
>
> I still not sure that I understand what you'd want. One generic data
> type for each possible alignment specification?

Ultimately, I'd like some way to tell the compiler what data, pointers 
and/or types can alias what.  But I'd settle for a set of types of 
different fixed sizes that may alias anything else.

"Restrict" is useful, and lets you tell the compiler that a particular 
char* pointer does not alias anything else.  But maybe I want to say the 
pointer doesn't alias other data - but it /might/ alias another char*. 
(OK, I'll accept that maybe I'm a little demanding here - after all, 
"restrict" handles most situations.  If only it worked in C++...)

>
>> So I would like to see types other than inefficient 8-bit types that
>> have the "alias everything" property, and 8-bit types that don't alias
>> anything.
>
> You mean that any "char*" parameter to a function could ruin some
> optimization? Never thought of it like that. But if you have a "char*"
> (and not "char const*") then probably it is a good idea to add a
> "restrict" where ever you may.

I doubt if there would actually be many missed optimisations in 
practice, but the fact that the char* may alias any data will mean that 
sometimes the compiler will have to commit stores that could otherwise 
be kept in registers, or re-load data from memory that could otherwise 
have been re-used from registers.  (Most of the targets I use have lots 
of registers - x86 users won't see this sort of effect.)

>
>> An alternative is to be able to specify aliasing more conveniently,
>> without having to use type-punning unions.
>
> "uintXX_t*" would be good candidates, here.

Yes, except that the compiler can assume that these will never alias 
incompatible types.

In effect, the compiler can treat "uint16_t * p16" and "uint32_t * p32" 
as though there is a "restrict" qualifier that declares that their 
memory does not coincide.  There is no good way to tell the compiler 
that they might, in fact, coincide.

>
>>>
>>>> Proper, standardised memory barriers of different types and granularity
>>>> would be a help for some low-level programming.
>>>
>>> My understanding is that these are included in C11 atomics, and since
>>> this part basically identical to C++11, it should be there, too.
>>
>> Well, atomics helps a bit - but they are overkill.  Mostly all you need
>> is to be able to say "make sure the store to variable X is completed
>> here", or "don't move the read before this point".  You can get a fair
>> amount of this using volatile accesses, but sometimes it is much more
>> convenient with general barriers.  Depending on the target cpu, you may
>> also want the barriers to issue additional instructions to flush buffers.
>
> Declaring a variable that you'd want to flush as atomic would
> certainly be overkill. But I don't see completely why
>
> atomic_thread_fence
>
> couldn't serve your purpose, at least aproximatively. True, it doesn't
> ensure a fence for just one variable, but then again with aliasing
> you'd have to make pretty much sure that your memory bus calmed down
> before supposing that no other variable is affected by a load or
> store. So my idea would be that atomic_thread_fence with a careful
> selection of the memory_order that you pass as argument would come
> relatively close to what you want.
>
> Jens
>

The atomic_thread_fence may be an answer here.  I'll need to wait a bit 
for support to make it into the tools I use, and then see what the code 
is actually generated for it (and for the atomic types).  But it is 
always possible that I'll be able to strike this one from my wishlist.

mvh.,

David

0
david2384 (2168)
8/28/2012 1:32:12 PM
On 08/28/2012 04:21 AM, David Brown wrote:
....
> Basically, I just want to be able to mix and match C and C++ code 
> freely.  I want to be able to write in the same style in each language. 
>   If I am not using C++ features, I want the code to be compilable as C 
> or C++, with the same functionality each time.  And I want to be able to 
> do so without artificially restricting the features I can use in C. 
> It's okay if I have to #include a few standard headers, and put in a few 
> extern "C" wrappers.
> 
> Am I really asking too much?

Yes, you are. In essence, what you're really asking for is a single
language (we could call it "C/C++", converting a popular misconception
into reality :-) ), with two modes it can be used in. What you're
actually faced with is two different languages, and it really doesn't
make sense for either one of them to be as tightly integrated with the
other as they would have to be to make what you want work.

If you can convince the C++ committee to port over a few more of C's new
features, then the C subset of C++ would provide virtually everything
you're asking for of C. That's a far more feasible goal to achieve than
integrating C and C++ together as tightly as you want.
-- 
James Kuyper
0
jameskuyper (5635)
8/28/2012 1:42:58 PM
On 28/08/2012 15:42, James Kuyper wrote:
> On 08/28/2012 04:21 AM, David Brown wrote:
> ...
>> Basically, I just want to be able to mix and match C and C++ code
>> freely.  I want to be able to write in the same style in each language.
>>    If I am not using C++ features, I want the code to be compilable as C
>> or C++, with the same functionality each time.  And I want to be able to
>> do so without artificially restricting the features I can use in C.
>> It's okay if I have to #include a few standard headers, and put in a few
>> extern "C" wrappers.
>>
>> Am I really asking too much?
>
> Yes, you are. In essence, what you're really asking for is a single
> language (we could call it "C/C++", converting a popular misconception
> into reality :-) ), with two modes it can be used in. What you're
> actually faced with is two different languages, and it really doesn't
> make sense for either one of them to be as tightly integrated with the
> other as they would have to be to make what you want work.
>
> If you can convince the C++ committee to port over a few more of C's new
> features, then the C subset of C++ would provide virtually everything
> you're asking for of C. That's a far more feasible goal to achieve than
> integrating C and C++ together as tightly as you want.
>

I'd be happy enough with a reasonable common subset - but bigger than 
there is today.  For example, I don't mind putting casts at void* 
pointers, and clearly I'd be happy avoiding C variables called "new" or 
"class".  I don't really count such things as "artificial" restrictions 
of C features.  But things like designated initialisers or "restrict" 
pointers /are/ artificial restrictions since there is no particular 
reason they can't be added to C++.

(To be honest, I can get much of this with gcc - it allows a wider 
common subset in both languages as an extension.  But it would be nice 
to see it in the standards.)

0
david2384 (2168)
8/28/2012 1:59:00 PM
Am 28.08.2012 15:32, schrieb David Brown:
> On 28/08/2012 14:06, Jens Gustedt wrote:
>> Am 28.08.2012 12:40, schrieb David Brown:
>>> On 27/08/2012 18:34, Jens Gustedt wrote:
>>>> Am 27.08.2012 10:40, schrieb David Brown:
>>>>> If someone is making a wish list here, I'd add support for defining
>>>>> endianness (allowing code to explicitly define and use variables and
>>>>> types as big endian or little endian independently of the
>>>>> architecture)
>>>>
>>>>
>>>>> and bit field ordering.
>>>>
>>>> I think this is more strictly defined for C already than for C++,
>>>> perhaps the definition that C has would be sufficient for your needs?
>>>>
>>>
>>> No, it is not defined nearly well enough.
>>>
>>> There are ambiguities regarding padding, alignment, etc., especially as
>>> the size of the fields change.  Different underlying types of the fields
>>> can make a difference (especially if you want something like an enum
>>> type),
>>
>> well C does only allow enums as implementation specific. For C the
>> only portable types are of signed and unsigned int and _Bool.
>>
>> And the only real ambiguity that I see is for bit-fields that may
>> cross storage boundaries, here the standard allows either realize part
>> of the bitfield in one unit and the other part in the other or to
>> accumulate them in the second unit. As long as all bits fit, they must
>> be placed in the same unit, and if you want to force it to move to the
>> next unit you can place a :0.
>>
> 
> That's true - but I want to be able to unambiguously place fields across
> boundaries, and I want to be able to use fields of different types in a
> well-defined, portable and cross-platform way.  For example, I want to
> be able to write:
> 
> struct {
>     uint8_t a;
>     uint8_t b;
>     uint8_t c : 4;
>     uint8_t d : 4;
>     uint8_t e;
> }
> 
> I want to be guaranteed that this struct takes 32 bits, and is aligned
> to 8-bit boundaries.

In C this

struct {
    unsigned a : 8;
    unsigned b : 8;
    unsigned c : 4;
    unsigned d : 4;
    unsigned e : 8;
}

should do what you want, provided CHAR_BITS is 8. Wouldn't that be
acceptable for you? I find it even clearer in its intent.

(Bitfields are guaranteed to have no padding and uint8_t is pretty
useless other than to guarantee that padding property or that its size
is 1.)

> The atomic_thread_fence may be an answer here.  I'll need to wait a bit
> for support to make it into the tools I use, and then see what the code
> is actually generated for it (and for the atomic types).  But it is
> always possible that I'll be able to strike this one from my wishlist.

What I have seen so far of the preliminary implementations in gcc and
clang it looked quite ok, there.

> mvh.,

?

Jens
0
8/28/2012 2:04:47 PM
Here is: 'Real defloration little girl'
(http://do18let.ru/forumdisplay.php?f=2)


-- 
Musysaurb
------------------------------------------------------------------------
Musysaurb's Profile: http://forums.yourdomain.com.au/member.php?userid=824
View this thread: http://forums.yourdomain.com.au/showthread.php?t=5300

0
8/28/2012 3:55:31 PM
On 28/08/2012 16:04, Jens Gustedt wrote:
> Am 28.08.2012 15:32, schrieb David Brown:
>> On 28/08/2012 14:06, Jens Gustedt wrote:
>>> Am 28.08.2012 12:40, schrieb David Brown:
>>>> On 27/08/2012 18:34, Jens Gustedt wrote:
>>>>> Am 27.08.2012 10:40, schrieb David Brown:
>>>>>> If someone is making a wish list here, I'd add support for defining
>>>>>> endianness (allowing code to explicitly define and use variables and
>>>>>> types as big endian or little endian independently of the
>>>>>> architecture)
>>>>>
>>>>>
>>>>>> and bit field ordering.
>>>>>
>>>>> I think this is more strictly defined for C already than for C++,
>>>>> perhaps the definition that C has would be sufficient for your needs?
>>>>>
>>>>
>>>> No, it is not defined nearly well enough.
>>>>
>>>> There are ambiguities regarding padding, alignment, etc., especially as
>>>> the size of the fields change.  Different underlying types of the fields
>>>> can make a difference (especially if you want something like an enum
>>>> type),
>>>
>>> well C does only allow enums as implementation specific. For C the
>>> only portable types are of signed and unsigned int and _Bool.
>>>
>>> And the only real ambiguity that I see is for bit-fields that may
>>> cross storage boundaries, here the standard allows either realize part
>>> of the bitfield in one unit and the other part in the other or to
>>> accumulate them in the second unit. As long as all bits fit, they must
>>> be placed in the same unit, and if you want to force it to move to the
>>> next unit you can place a :0.
>>>
>>
>> That's true - but I want to be able to unambiguously place fields across
>> boundaries, and I want to be able to use fields of different types in a
>> well-defined, portable and cross-platform way.  For example, I want to
>> be able to write:
>>
>> struct {
>>      uint8_t a;
>>      uint8_t b;
>>      uint8_t c : 4;
>>      uint8_t d : 4;
>>      uint8_t e;
>> }
>>
>> I want to be guaranteed that this struct takes 32 bits, and is aligned
>> to 8-bit boundaries.
>
> In C this
>
> struct {
>      unsigned a : 8;
>      unsigned b : 8;
>      unsigned c : 4;
>      unsigned d : 4;
>      unsigned e : 8;
> }
>
> should do what you want, provided CHAR_BITS is 8. Wouldn't that be
> acceptable for you? I find it even clearer in its intent.
>
> (Bitfields are guaranteed to have no padding and uint8_t is pretty
> useless other than to guarantee that padding property or that its size
> is 1.)
>

In practice, this works fine - but the guarantees in the standard are 
weak.  I /use/ bitfields regularly, with different types and enum types 
in the bitfields.  But I would prefer that the standards said that such 
usage was completely well-defined.

>> The atomic_thread_fence may be an answer here.  I'll need to wait a bit
>> for support to make it into the tools I use, and then see what the code
>> is actually generated for it (and for the atomic types).  But it is
>> always possible that I'll be able to strike this one from my wishlist.
>
> What I have seen so far of the preliminary implementations in gcc and
> clang it looked quite ok, there.
>

It will be fun to try it out.  For my professional work, I am reliant on 
"official" builds of gcc from various sources for various targets (as 
well as a few other non-gcc compilers), but I like to keep track of the 
latest developments too.

>> mvh.,
>

"Med vennlig hilsen" - "with friendly greetings" in Norwegian.  It's a 
habit, and I sometimes use it in English-language emails without 
thinking about it.

>
> Jens
>

0
david2384 (2168)
8/28/2012 3:57:55 PM
On 08/28/2012 09:32 AM, David Brown wrote:
....
> Ultimately, I'd like some way to tell the compiler what data, pointers 
> and/or types can alias what.

If you put two types in a union, within the scope of that union
declaration a conforming implementation must take aliasing between those
two types into consideration any time it's dealing with pointers that
could be pointing at different members of the same union object.

This won't help you, of course, if you want it to consider aliasing in
contexts where it's impossible that they refer to the same union object.
0
jameskuyper (5635)
8/28/2012 4:39:48 PM
Am 28.08.2012 17:57, schrieb David Brown:
>> In C this
>>
>> struct {
>>      unsigned a : 8;
>>      unsigned b : 8;
>>      unsigned c : 4;
>>      unsigned d : 4;
>>      unsigned e : 8;
>> }
>>
>> should do what you want, provided CHAR_BITS is 8. Wouldn't that be
>> acceptable for you? I find it even clearer in its intent.
>>
>> (Bitfields are guaranteed to have no padding and uint8_t is pretty
>> useless other than to guarantee that padding property or that its size
>> is 1.)
>>
> 
> In practice, this works fine - but the guarantees in the standard are
> weak.  I /use/ bitfields regularly, with different types and enum types
> in the bitfields.  But I would prefer that the standards said that such
> usage was completely well-defined.

can't agree on that, the standard describes exactly how this has to be
layed out. (well it could decide to pad it to 64 bit, but that's it.)

>>> The atomic_thread_fence may be an answer here.  I'll need to wait a bit
>>> for support to make it into the tools I use, and then see what the code
>>> is actually generated for it (and for the atomic types).  But it is
>>> always possible that I'll be able to strike this one from my wishlist.
>>
>> What I have seen so far of the preliminary implementations in gcc and
>> clang it looked quite ok, there.
>>
> 
> It will be fun to try it out.  For my professional work, I am reliant on
> "official" builds of gcc from various sources for various targets (as
> well as a few other non-gcc compilers), but I like to keep track of the
> latest developments too.

starting with gcc 4.7 they have moved to new interfaces for the
builtins that come close to what the standards (C and C++) describe

>>> mvh.,
>>
> 
> "Med vennlig hilsen" - "with friendly greetings" in Norwegian.  It's a
> habit, and I sometimes use it in English-language emails without
> thinking about it.

ah, my first name might have triggered that reflex

Jens
0
8/28/2012 4:45:17 PM
On Tuesday, August 28, 2012 4:32:56 PM UTC+3, David Brown wrote:
> well-defined, portable and cross-platform way.  For example, I want to 
> be able to write:
> 
> struct {
> 	uint8_t a;
> 	uint8_t b;
> 	uint8_t c : 4;
> 	uint8_t d : 4;
> 	uint8_t e;
> }

It is unlikely that C++ will allow nameless structs and unions ever again.

> I want to be guaranteed that this struct takes 32 bits, and is aligned 
> to 8-bit boundaries.

static_assert about sizeof guarantees that it won't compile. For bit order
and padding you need bit more complex static asserts.    

As about keywords like 'restrict', 'inline' or 'register' i am sure that on general case compiler and/or linker can optimize lot better than average Joe and so the keywords just add pointless bloat.
0
ootiib (965)
8/28/2012 5:14:49 PM
On 2012-08-27 22:34, BGB wrote:
>> Definition of NULL as ((void*)0) is contingent on the implicit
>> conversion of void* to other pointer types.
>>
>
> well, yes, but I listed that they could add this as well.
> probably most C++ code wouldn't notice the change.

I should have been more clear about my point here: I was trying to say 
that the only reason this definition of NULL is unacceptable to C++ is 
because of the lack of the implicit conversion from void*. Given that 
conversion, there would be no other barrier in C++ to using ((void*)0) 
for NULL.

> possibly, the change could be limited to 'extern "C"' code or similar
> (and/or could be ignored in cases of templates or overloading, or at
> least be a lower priority than any other matches).

I think the rules for overload resolution and template type deduction 
are complicated enough without introducing a feature that behaves 
differently depending on whether or not it interacts with those systems.

There's no such thing as 'extern "C" code': extern "foo" is a *linkage 
specification* whose sole purpose is to tell the implementation to 
engage the ABI machinery appropriate for language "foo".

>> That implicit conversion from void* to any pointer type is a dangerous
>> hole in the type system. I admit I'm not much of a C programmer anymore:
>> the only valid reason I can think of to have this conversion is so that
>> malloc calls don't require you to specify the type _three_ times (e.g.,
>> int* p = (int*)malloc(sizeof(*p)); ).
>>
>
> there are plenty of uses besides malloc, so malloc is just one of many
> cases (mmap, memcpy, VirtualAlloc, ...).
>
> or, a biggie:
> for any user-defined code which accepts or returns "void *".

Returns, not accepts. The implicit conversion _from_ void* is dangerous, 
implicit conversion _to_ void* is perfectly safe type erasure.

>
> for example, to do similar tasks in C++ often requires a larger number
> of casts.
>
>
>> If I really wanted to pitch the committees for stronger ties between C
>> and C++, I'd probably suggest that (a) C pick up nullptr (and nullptr_t)
>> to serve as generic null pointer constant,
>
> could work...
>
>
>> (b) C drop the implicit
>> conversion from void*,
>
> this would break large amounts of C code.

I'll handwave here and claim that's what compiler options are for. Valid 
C90 code will always be valid C90 code, I see no reason why a future C20 
compiler couldn't be instructed to compile code as C90. Old code will 
always be old code, but does that mean that we have to keep on writing 
old code forever?

It's already the case that C11 made some C99 features optional: there 
may be conforming C11 compilers that refuse to compile some conforming 
C99 programs. The kind of change I suggest is quantitatively but not 
qualitatively different.

> I don't think people on either side would want changes which cause their
> existing programs to break and have to be rewritten.
>
>> and (c) both languages use a new distinct type
>> that can implicitly convert to any pointer type.
>
> we call this 'void *', where this is nearly the only thing that can
> really be done with this type anyways ("void" variables are otherwise
> pretty much useless, ...).

I am differentiating between the implicit conversion _from_ any pointer 
type and the implicit conversion _to_ any pointer type; I posit that 
those two features have unique design intentions and should therefore be 
represented by distinct types. C conflates the two ideas in void*, C++ 
doesn't have the conversion _to_ any pointer type at all, except for 
nullptr. (Given how simple it is to make a user-defined type in C++ that 
implicitly converts to any pointer type, it's notable that I've never 
seen anyone feel the need to do so.)

void* has 2 uses in C:
1. it's the "sink" type to which all other pointer types can be 
implicitly converted.
2. it's the "source" type that implicitly converts to all other pointer 
types.

and 2 uses in C++:
1. "sink" type just as in C.
2. type-erased pointer that designates _some_kind_ of object about which 
nothing is known except its location in memory.

The secondary usage is diametrically opposite between C and C++: one 
disallows using a void* for any purpose without a cast, the other allows 
you to pass a void* where you would any pointer type without a cast. In 
C, I can pass the same void* to fclose, free, strcat, and 
hundreds/thousands of other functions without a compiler diagnostic. 
Using void* you've effectively opted out of a large part of the type system.

C programmers also often use void* as either a type-erased or generic 
pointer but do so purely based on convention and discipline: you will 
get no help from the compiler. If an intern jumps into your code the 
next day and passes your type-erased pointer to fputs, the compiler will 
accept it happily.

>  > Holes in the type
>> system are very useful at the fringes of C/C++ programs, I think that
>> having distinct "source" (X -> any*) and "sink" (any* -> X) pointer
>> types preserves the utility of C-style void* while minimizing the danger.
>
> yes, but the least impact route would be to just pick up C's "void *"
> semantics for this, since C++ code isn't likely to notice, and existing
> C code can keep working unmodified.

While it's true that making the language more permissive doesn't impact 
the correctness of existing programs, that doesn't necessarily make it 
always a good idea. I seriously doubt that the C++ community would ever 
accept implicit conversion from void* into the language; the case I'm 
attempting to make here is that C shouldn't have that feature either and 
likely would not if it was designed afresh today.

Given that preserving the semantics of old code has a higher priority to 
the C community than almost any other concern, I think it's unlikely 
that we will ever have a C++ that is truly a superset of C.  If anything 
I think it's more likely that C++ would introduce even more breaking 
changes to become _less_ compatible with C.
0
8/28/2012 5:18:33 PM
On 2012-08-28 02:27, Jens Gustedt wrote:
> That said, I don't really see the point of "void*" as it is in C++
> nowadays. Since you'd have to do an explicit conversion any time you
> use it, in C++ it has nothing that couldn't be done with a "unsigned
> char*". In the contrary, "unsigned char*" allows byte based pointer
> arithmetic and to inspect the contents on a byte base.
>
> The only reason, I think, for "void*" is interface compability to
> C. Somehow it misses the whole point of it.
>
> Jens
>

The point of a type system is to restrict what operations are valid, so 
void* is desirable in C++ precisely because there are _fewer_ things you 
can do with it than unsigned char*.
0
8/28/2012 5:24:15 PM
On 8/28/2012 12:18 PM, Casey Carter wrote:
> On 2012-08-27 22:34, BGB wrote:
>>> Definition of NULL as ((void*)0) is contingent on the implicit
>>> conversion of void* to other pointer types.
>>>
>>
>> well, yes, but I listed that they could add this as well.
>> probably most C++ code wouldn't notice the change.
>
> I should have been more clear about my point here: I was trying to say
> that the only reason this definition of NULL is unacceptable to C++ is
> because of the lack of the implicit conversion from void*. Given that
> conversion, there would be no other barrier in C++ to using ((void*)0)
> for NULL.
>

yep, which is probably why they could do it...
it does at least make more sense than defining it as 0 (which would give 
a warning in C).

possible could be changing it internally to _Nullptr or similar, which 
could be defined as "functionally equivalent to ((void *)0)".


>> possibly, the change could be limited to 'extern "C"' code or similar
>> (and/or could be ignored in cases of templates or overloading, or at
>> least be a lower priority than any other matches).
>
> I think the rules for overload resolution and template type deduction
> are complicated enough without introducing a feature that behaves
> differently depending on whether or not it interacts with those systems.
>
> There's no such thing as 'extern "C" code': extern "foo" is a *linkage
> specification* whose sole purpose is to tell the implementation to
> engage the ABI machinery appropriate for language "foo".
>

they *could* make it work this way, but OTOH, maybe it isn't such a 
great idea to add context-sensitivity in this case.

otherwise, C's "void *" semantics would then apply everywhere.


>>> That implicit conversion from void* to any pointer type is a dangerous
>>> hole in the type system. I admit I'm not much of a C programmer anymore:
>>> the only valid reason I can think of to have this conversion is so that
>>> malloc calls don't require you to specify the type _three_ times (e.g.,
>>> int* p = (int*)malloc(sizeof(*p)); ).
>>>
>>
>> there are plenty of uses besides malloc, so malloc is just one of many
>> cases (mmap, memcpy, VirtualAlloc, ...).
>>
>> or, a biggie:
>> for any user-defined code which accepts or returns "void *".
>
> Returns, not accepts. The implicit conversion _from_ void* is dangerous,
> implicit conversion _to_ void* is perfectly safe type erasure.
>

but, changing this behavior would break existing code.

consider you have something like:
Foo *obj;
obj=gcalloc(sizeof(Foo)); //allocated via a GC API
which would need to be changed everywhere to:
obj=(Foo *)gcalloc(sizeof(Foo)); //allocated via a GC API

this kind of thing isn't really a good option.

introducing another pointer type similarly has the problem of requiring 
changing existing code to make it work (altering use of "void *" return 
types), which is similarly not a good option.


>>
>> for example, to do similar tasks in C++ often requires a larger number
>> of casts.
>>
>>
>>> If I really wanted to pitch the committees for stronger ties between C
>>> and C++, I'd probably suggest that (a) C pick up nullptr (and nullptr_t)
>>> to serve as generic null pointer constant,
>>
>> could work...
>>
>>
>>> (b) C drop the implicit
>>> conversion from void*,
>>
>> this would break large amounts of C code.
>
> I'll handwave here and claim that's what compiler options are for. Valid
> C90 code will always be valid C90 code, I see no reason why a future C20
> compiler couldn't be instructed to compile code as C90. Old code will
> always be old code, but does that mean that we have to keep on writing
> old code forever?
>

actually, I was thinking if C99 or C11 were the subset, not C90.
in both cases, "void *" works as it did before.


> It's already the case that C11 made some C99 features optional: there
> may be conforming C11 compilers that refuse to compile some conforming
> C99 programs. The kind of change I suggest is quantitatively but not
> qualitatively different.
>

it would break the majority of existing code, rather than just "some 
code which uses a few features which never gained widespread adoption 
anyways" (or "something which has largely fallen into disuse"), this is 
a bit more severe, as it would break "nearly all existing C programs"...


>> I don't think people on either side would want changes which cause their
>> existing programs to break and have to be rewritten.
>>
>>> and (c) both languages use a new distinct type
>>> that can implicitly convert to any pointer type.
>>
>> we call this 'void *', where this is nearly the only thing that can
>> really be done with this type anyways ("void" variables are otherwise
>> pretty much useless, ...).
>
> I am differentiating between the implicit conversion _from_ any pointer
> type and the implicit conversion _to_ any pointer type; I posit that
> those two features have unique design intentions and should therefore be
> represented by distinct types. C conflates the two ideas in void*, C++
> doesn't have the conversion _to_ any pointer type at all, except for
> nullptr. (Given how simple it is to make a user-defined type in C++ that
> implicitly converts to any pointer type, it's notable that I've never
> seen anyone feel the need to do so.)
>
> void* has 2 uses in C:
> 1. it's the "sink" type to which all other pointer types can be
> implicitly converted.
> 2. it's the "source" type that implicitly converts to all other pointer
> types.
>
> and 2 uses in C++:
> 1. "sink" type just as in C.
> 2. type-erased pointer that designates _some_kind_ of object about which
> nothing is known except its location in memory.
>
> The secondary usage is diametrically opposite between C and C++: one
> disallows using a void* for any purpose without a cast, the other allows
> you to pass a void* where you would any pointer type without a cast. In
> C, I can pass the same void* to fclose, free, strcat, and
> hundreds/thousands of other functions without a compiler diagnostic.
> Using void* you've effectively opted out of a large part of the type
> system.
>
> C programmers also often use void* as either a type-erased or generic
> pointer but do so purely based on convention and discipline: you will
> get no help from the compiler. If an intern jumps into your code the
> next day and passes your type-erased pointer to fputs, the compiler will
> accept it happily.
>


actually, C code typically handles the type-erased case by defining new 
types based on incomplete structs or similar, as in:
typedef struct _opaqueptr_s opaqueptr_t;

so, this isn't really an issue in practice.


>>  > Holes in the type
>>> system are very useful at the fringes of C/C++ programs, I think that
>>> having distinct "source" (X -> any*) and "sink" (any* -> X) pointer
>>> types preserves the utility of C-style void* while minimizing the
>>> danger.
>>
>> yes, but the least impact route would be to just pick up C's "void *"
>> semantics for this, since C++ code isn't likely to notice, and existing
>> C code can keep working unmodified.
>
> While it's true that making the language more permissive doesn't impact
> the correctness of existing programs, that doesn't necessarily make it
> always a good idea. I seriously doubt that the C++ community would ever
> accept implicit conversion from void* into the language; the case I'm
> attempting to make here is that C shouldn't have that feature either and
> likely would not if it was designed afresh today.
>
> Given that preserving the semantics of old code has a higher priority to
> the C community than almost any other concern, I think it's unlikely
> that we will ever have a C++ that is truly a superset of C.  If anything
> I think it's more likely that C++ would introduce even more breaking
> changes to become _less_ compatible with C.

well, one could always argue that, on the other side, it may be that C 
is already good and that it is C++ which needs changing to be more 
compatible with C, but either way.


usually, the route of least impact is the most preferable, and simply 
adding "void*" is what leads to this.


the other possible option is, granted, the introduction of an explicit 
"C mode" into the compiler, which could possibly look like 'extern "C"' 
but would infact change the semantics, or maybe, the introduction of new 
syntax for this case, say:
_C { ... }

which would both enable C style linkage, as well as switching over to C 
style semantics as well.

maybe it could also be used to declare functions with C-style semantics 
(but retaining C++ linkage), as-in:
void myfunc(void) _C
{
	Foo *obj;
	obj=malloc(sizeof(Foo));
	...
}

then C compilers would simply ignore the _C modifier (that or it is 
handled similarly to how 'extern "C"' is generally handled in headers, 
IOW, via preprocessor magic).

maybe it could be called something like:
C_MODE

and would be defined something like:
#ifndef C_MODE
#ifdef __cplusplus
#define C_MODE _C
#else
#define C_MODE
#endif
#endif


or, something along these lines...

0
cr88192355 (1928)
8/28/2012 6:00:13 PM
Jens Gustedt <jens.gustedt@loria.fr> writes:
>Am 28.08.2012 17:57, schrieb David Brown:
>>> In C this
>>>
>>> struct {
>>>      unsigned a : 8;
>>>      unsigned b : 8;
>>>      unsigned c : 4;
>>>      unsigned d : 4;
>>>      unsigned e : 8;
>>> }
>>>
>>> should do what you want, provided CHAR_BITS is 8. Wouldn't that be
>>> acceptable for you? I find it even clearer in its intent.
>>>
>>> (Bitfields are guaranteed to have no padding and uint8_t is pretty
>>> useless other than to guarantee that padding property or that its size
>>> is 1.)
>>>
>> 
>> In practice, this works fine - but the guarantees in the standard are
>> weak.  I /use/ bitfields regularly, with different types and enum types
>> in the bitfields.  But I would prefer that the standards said that such
>> usage was completely well-defined.
>
>can't agree on that, the standard describes exactly how this has to be
>layed out. (well it could decide to pad it to 64 bit, but that's it.)

Until you build code that must compile and run on both big-endian and
little-endian architectures, where the order of the bits _will_ change. Not
a problem unless the bits are mapped to hardware or are serialized as a
larger unit (e.g. uint32_t).

z.b.:

    union u_reg_0x351 {
        uint32  u32;
        struct {
            uint32
#if __BYTE_ORDER__ == __BIG_ENDIAN
                      :27,
                enable:1,   // [4]  Enable access
                dsb:1,      // [3]  Disable S Bypass
                dib:1,      // [2]  Disable I Bypass
                dfb:1,      // [1]  Disable F Bypass
                sre:1;      // [0]  System Register Enable
#else
                sre:1,      // [0] System Register Enable
                dfb:1,      // [1]  Disable F Bypass
                dib:1,      // [2]  Disable I Bypass
                dsb:1,      // [3]  Disable S Bypass
                enable:1,   // [4]  Enable access
                      :27;
#endif
        } s;
    };


0
scott1 (423)
8/28/2012 6:08:14 PM
Jens Gustedt wrote 2012-08-27 18:34:

> I am not sure that I understand this one. C has the optional uintXX_t
> that are guaranteed to have a fixed width no padding etc, if they
> exist. Would it for your purpose just suffice to make some of these
> types mandatory e.g for 8, 16, 32 and 64 bit integers?
>

Why would you want to make this mandatory for everyone? Why not be 
satisfied if your code is portable to systems having these types?

Whatever we do at the language level, we still have code that will not 
run both on a cell phone and a supercomputer. In places where the 
language standards are vague, it is to ALLOW for implementations on 
other types of systems.

For example, I write some code for IBM mainframes. It will not run at 
all on any systems not having IMS and DB2. It is totally non-portable 
whatever language features we use. Just let us do that!


Bo Persson


0
bop (1086)
8/28/2012 6:38:17 PM
Am 28.08.2012 20:08, schrieb Scott Lurndal:
> Jens Gustedt <jens.gustedt@loria.fr> writes:

> Until you build code that must compile and run on both big-endian and
> little-endian architectures, where the order of the bits _will_ change. Not
> a problem unless the bits are mapped to hardware or are serialized as a
> larger unit (e.g. uint32_t).

ah ok, the standard effectively only make a statement about the value
(bit pattern seen as unsigned value) of such a beast. How and in which
order this is stored depends on endianess of the architecture. But
that is not a problem of bit-fields per se, but the fact that C still
has to run on two different types of architectures with respect to
that.

Jens
0
8/28/2012 6:44:58 PM
On 08/28/2012 12:45 PM, Jens Gustedt wrote:
> Am 28.08.2012 17:57, schrieb David Brown:
>>> In C this
>>>
>>> struct {
>>>      unsigned a : 8;
>>>      unsigned b : 8;
>>>      unsigned c : 4;
>>>      unsigned d : 4;
>>>      unsigned e : 8;
>>> }
>>>
>>> should do what you want, provided CHAR_BITS is 8. Wouldn't that be
>>> acceptable for you? I find it even clearer in its intent.
>>>
>>> (Bitfields are guaranteed to have no padding and uint8_t is pretty
>>> useless other than to guarantee that padding property or that its size
>>> is 1.)
>>>
>>
>> In practice, this works fine - but the guarantees in the standard are
>> weak.  I /use/ bitfields regularly, with different types and enum types
>> in the bitfields.  But I would prefer that the standards said that such
>> usage was completely well-defined.
> 
> can't agree on that, the standard describes exactly how this has to be
> layed out. (well it could decide to pad it to 64 bit, but that's it.)

That's not consistent with my understanding of the standard. Could you
specify precisely how you thought the standard required that structure
to be laid out?

The relevant clause from the C standard is 6.7.2.1p11:
> An implementation may allocate any addressable storage unit large enough to hold a bitfield.
> If enough space remains, a bit-field that immediately follows another bit-field in a
> structure shall be packed into adjacent bits of the same unit. If insufficient space remains,
> whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is
> implementation-defined. The order of allocation of bit-fields within a unit (high-order to
> low-order or low-order to high-order) is implementation-defined. The alignment of the
> addressable storage unit is unspecified.

In the C++ standard, 9.6p1 says much the same thing, in somewhat less
formal language.

Neither standard specifies the size of the allocation unit from which
bit-fields are allocated. Which size were you assuming was specified by
the standard?

If there's enough space to store b in the same allocation unit as 'a',
the C standard requires that 'b' be stored in bits adjacent to 'a', but
it does not specify the relative order of 'a' and 'b'. Both standards
explicitly state that the order of bit-fields within an allocation unit
is unspecified . What order were you assuming was specified by the standard?

Both standards explicitly leave unspecified whether bit-fields can
overlap adjacent allocation units. Since the assumption that CHAR_BIT==8
was specified, that problem won't come up in this particular case, but
with different bit-field sizes, or even with the same sizes in a
different order, that could be an issue even on entirely conventional
systems. For instance, if "c" were moved before "b", and the allocation
unit was either 8 or 16 bits in size, then "b" might, or might not,
overlap two consecutive allocation unit, depending upon the
implementation. Were you making any assumptions about how such overlaps
would be handled, or were you relying upon the assumption that
CHAR_BIT==8 to conclude that this particular structure has a uniquely
specified layout?

0
jameskuyper (5635)
8/28/2012 6:50:20 PM
BGB wrote 2012-08-28 05:34:
> On 8/27/2012 9:47 PM, Casey Carter wrote:
>
>> That implicit conversion from void* to any pointer type is a dangerous
>> hole in the type system. I admit I'm not much of a C programmer anymore:
>> the only valid reason I can think of to have this conversion is so that
>> malloc calls don't require you to specify the type _three_ times (e.g.,
>> int* p = (int*)malloc(sizeof(*p)); ).
>>
>
> there are plenty of uses besides malloc, so malloc is just one of many
> cases (mmap, memcpy, VirtualAlloc, ...).

But you don't use memcpy for C++ type, you use std::copy which is typed. 
And you don't do malloc either, you use the containers from the C++ 
standard library. Or use the occasional new X, which doesn't need a cast 
either.

>
> or, a biggie:
> for any user-defined code which accepts or returns "void *".

No, these can be templates and accept or return T*, for any type T.

>
> for example, to do similar tasks in C++ often requires a larger number
> of casts.

If you do it the C++ way, it actually uses fewer casts.  :-)


A big problem with trying to finds the common ground between C and C++ 
is that lots of good C++ code isn't using many C features at all. And 
well written C code tend to be very non-idiomatic C++ code.


Bo Persson

0
bop (1086)
8/28/2012 6:58:49 PM
Am 28.08.2012 19:24, schrieb Casey Carter:
> On 2012-08-28 02:27, Jens Gustedt wrote:
>> That said, I don't really see the point of "void*" as it is in C++
>> nowadays. Since you'd have to do an explicit conversion any time you
>> use it, in C++ it has nothing that couldn't be done with a "unsigned
>> char*". In the contrary, "unsigned char*" allows byte based pointer
>> arithmetic and to inspect the contents on a byte base.
>>
>> The only reason, I think, for "void*" is interface compability to
>> C. Somehow it misses the whole point of it.
>>
>> Jens
>>
> 
> The point of a type system is to restrict what operations are valid,

sure

> so void* is desirable in C++ precisely because there are _fewer_
> things you can do with it than unsigned char*.

my question would be more, why would you need it at all? Where does
the idea of having a pointer that has no type information occur in
C++? In C++ all objects have a type from their creation ("new" always
generates a typed object) and all other stuff is regulated through the
different forms of cast, inheritence and all that. If you want to do
it really badly, you'd do a reintrepret_cast anyhow, no need to go
through "void*", no? I think C++ itself doesn't need "void*" much and
the use of it is rightly frowned upon in C++. (Well there are some
very restricted corner cases such as overloading "operator new" or
things like that.)

You need "void*" when you use "malloc" or other stuff for
compatibility with C. So why the hell have it function differently in
C++? This is just an inconvenience / annoyance.

Jens
0
8/28/2012 7:02:09 PM
Am 28.08.2012 13:04, schrieb Malcolm McLean:
> בתאריך יום שלישי, 28 באוגוסט 2012 08:27:55 UTC+1, מאת Jens Gustedt:
>> Am 28.08.2012 05:34, schrieb BGB:
>>
>>
>> That said, I don't really see the point of "void*" as it is in C++
>> nowadays. Since you'd have to do an explicit conversion any time you
>> use it, in C++ it has nothing that couldn't be done with a "unsigned
>> char*". In the contrary, "unsigned char*" allows byte based pointer
>> arithmetic and to inspect the contents on a byte base.
>>
> void * just documents that "this is an unsigned char * holding arbitrary 
> bytes". It's a bit pointless to require a cast to and from, because you
> can't use the data in any way without converting it to something else, 
> but that's just a minor syntactical niggle.

minor syntax problem, perhaps, but can be very anoying

In C, many agree that cast are to be avoided as much as possible,
because they often hide problems. Just introducing casts into code for
the only reason to have it compatible with C++ is a show stopper.

Jens


0
8/28/2012 7:06:13 PM
Jens Gustedt wrote 2012-08-28 21:02:

>
> You need "void*" when you use "malloc" or other stuff for
> compatibility with C. So why the hell have it function differently in
> C++? This is just an inconvenience / annoyance.
>

No, it was done on purpose.

If you write

MyClass* x = malloc(sizeof(MyClass));

you are in real trouble, because you forgot to call the constructor of 
MyClass. You really don't want to have that conversion by default.

In C this is less of a problem, because there is no constructor anyway.


Bo Persson




0
bop (1086)
8/28/2012 7:15:53 PM
On 08/27/2012 12:34 PM, Jens Gustedt wrote:
....
> ... C has the optional uintXX_t
> that are guaranteed to have a fixed width no padding etc, if they
> exist. Would it for your purpose just suffice to make some of these
> types mandatory e.g for 8, 16, 32 and 64 bit integers?

Implementations which fail to support those types do so almost
exclusively because there is no hardware support on the target platform
for a type that meet's the standard's specifications for those types.
Keep in mind that the specifications are such as to rule out emulation.
For instance, an emulated 32-bit type on a system with CHAR_BIT==9 could
be called int_least32_t, or int_fast32_t, but it could not meet the
requirements to qualify as int32_t, because it would have to occupy at
least 36 bits, and designating 4 of those bits as padding is not allowed
for int32_t.

The sole effect of making those types mandatory would be to render all
implementations targeting such platforms non-conforming. Such platforms
may currently be exceedingly rare, or even non-existent - but is there
any value to be gained by prohibiting implementations for such platforms
from claiming standard conformance?


0
jameskuyper (5635)
8/28/2012 7:24:32 PM
Am 28.08.2012 20:50, schrieb James Kuyper:
> On 08/28/2012 12:45 PM, Jens Gustedt wrote:
>> Am 28.08.2012 17:57, schrieb David Brown:
>>>> In C this
>>>>
>>>> struct {
>>>>      unsigned a : 8;
>>>>      unsigned b : 8;
>>>>      unsigned c : 4;
>>>>      unsigned d : 4;
>>>>      unsigned e : 8;
>>>> }
>>>>
>>>> should do what you want, provided CHAR_BITS is 8. Wouldn't that be
>>>> acceptable for you? I find it even clearer in its intent.
>>>>
>>>> (Bitfields are guaranteed to have no padding and uint8_t is pretty
>>>> useless other than to guarantee that padding property or that its size
>>>> is 1.)
>>>>
>>>
>>> In practice, this works fine - but the guarantees in the standard are
>>> weak.  I /use/ bitfields regularly, with different types and enum types
>>> in the bitfields.  But I would prefer that the standards said that such
>>> usage was completely well-defined.
>>
>> can't agree on that, the standard describes exactly how this has to be
>> layed out. (well it could decide to pad it to 64 bit, but that's it.)
> 
> That's not consistent with my understanding of the standard. Could you
> specify precisely how you thought the standard required that structure
> to be laid out?
> 
> The relevant clause from the C standard is 6.7.2.1p11:
>> An implementation may allocate any addressable storage unit large enough to hold a bitfield.
>> If enough space remains, a bit-field that immediately follows another bit-field in a
>> structure shall be packed into adjacent bits of the same unit. If insufficient space remains,
>> whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is
>> implementation-defined. The order of allocation of bit-fields within a unit (high-order to
>> low-order or low-order to high-order) is implementation-defined. The alignment of the
>> addressable storage unit is unspecified.
> 
> In the C++ standard, 9.6p1 says much the same thing, in somewhat less
> formal language.

I have the vague memory of someone claiming that C++ allowed for an
out of order storage of bit-fields, but I would be happy to learn the
contrary.

> Neither standard specifies the size of the allocation unit from which
> bit-fields are allocated. Which size were you assuming was specified by
> the standard?

It must be an addressable storage unit, so it must be a multiple of 8
bit (I assumed that CHAR_BITS is 8). So what ever multiple of 8 is
chosen for it c and d will always fit into the same unit. So the order
will always be a-b-c-d-e or the other way around.

> If there's enough space to store b in the same allocation unit as 'a',
> the C standard requires that 'b' be stored in bits adjacent to 'a', but
> it does not specify the relative order of 'a' and 'b'. Both standards
> explicitly state that the order of bit-fields within an allocation unit
> is unspecified . What order were you assuming was specified by the standard?
> 
> Both standards explicitly leave unspecified whether bit-fields can
> overlap adjacent allocation units. Since the assumption that CHAR_BIT==8
> was specified, that problem won't come up in this particular case, but
> with different bit-field sizes, or even with the same sizes in a
> different order, that could be an issue even on entirely conventional
> systems. For instance, if "c" were moved before "b", and the allocation
> unit was either 8 or 16 bits in size, then "b" might, or might not,
> overlap two consecutive allocation unit, depending upon the
> implementation.

I was refering to this example only. Perhaps you missed the fact that
I referred to the case of potential overlap upthread already and that
we were discussing a specific case here that came from an example by
David where he wanted a layout that respected byte (uint8_t)
boundaries.

But, point taken, it has two different layouts.

Jens
0
8/28/2012 8:36:01 PM
Am 28.08.2012 21:24, schrieb James Kuyper:
> On 08/27/2012 12:34 PM, Jens Gustedt wrote:
> ...
>> ... C has the optional uintXX_t
>> that are guaranteed to have a fixed width no padding etc, if they
>> exist. Would it for your purpose just suffice to make some of these
>> types mandatory e.g for 8, 16, 32 and 64 bit integers?
> 
> Implementations which fail to support those types do so almost
> exclusively because there is no hardware support on the target platform
> for a type that meet's the standard's specifications for those types.
> Keep in mind that the specifications are such as to rule out emulation.
> For instance, an emulated 32-bit type on a system with CHAR_BIT==9 could
> be called int_least32_t, or int_fast32_t, but it could not meet the
> requirements to qualify as int32_t, because it would have to occupy at
> least 36 bits, and designating 4 of those bits as padding is not allowed
> for int32_t.

exactly

> The sole effect of making those types mandatory would be to render all
> implementations targeting such platforms non-conforming. Such platforms
> may currently be exceedingly rare, or even non-existent - but is there
> any value to be gained by prohibiting implementations for such platforms
> from claiming standard conformance?

POSIX went that path, for example, so it seems that they got away with
it well.

And just think of it as a question, I didn't say that I want it
myself. You seem to be against, I wouldn't be sure.

Also I think that CHAR_BIT==9 could imply the existence of uint9_t,
wouldn't it? One could expect that it then has the types that
correspond to sizeof(int)*CHAR_BIT and similar multiples, no?

I was just trying what the original poster had in mind with his
question (which you completely snipped). I understood it that he
sought for a way to access "uninterpreted" larger chunks of objects,
where the chunks correspond to the typical sizes that arithmetic types
have.

Jens
0
8/28/2012 8:47:56 PM
On 08/28/2012 04:36 PM, Jens Gustedt wrote:
> Am 28.08.2012 20:50, schrieb James Kuyper:
>> On 08/28/2012 12:45 PM, Jens Gustedt wrote:
>>> Am 28.08.2012 17:57, schrieb David Brown:
>>>>> In C this
>>>>>
>>>>> struct {
>>>>>      unsigned a : 8;
>>>>>      unsigned b : 8;
>>>>>      unsigned c : 4;
>>>>>      unsigned d : 4;
>>>>>      unsigned e : 8;
>>>>> }
>>>>>
>>>>> should do what you want, provided CHAR_BITS is 8. Wouldn't that be
>>>>> acceptable for you? I find it even clearer in its intent.
>>>>>
>>>>> (Bitfields are guaranteed to have no padding and uint8_t is pretty
>>>>> useless other than to guarantee that padding property or that its size
>>>>> is 1.)
>>>>>
>>>>
>>>> In practice, this works fine - but the guarantees in the standard are
>>>> weak.  I /use/ bitfields regularly, with different types and enum types
>>>> in the bitfields.  But I would prefer that the standards said that such
>>>> usage was completely well-defined.
>>>
>>> can't agree on that, the standard describes exactly how this has to be
>>> layed out. (well it could decide to pad it to 64 bit, but that's it.)
>>
>> That's not consistent with my understanding of the standard. Could you
>> specify precisely how you thought the standard required that structure
>> to be laid out?
>>
>> The relevant clause from the C standard is 6.7.2.1p11:
>>> An implementation may allocate any addressable storage unit large enough to hold a bitfield.
>>> If enough space remains, a bit-field that immediately follows another bit-field in a
>>> structure shall be packed into adjacent bits of the same unit. If insufficient space remains,
>>> whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is
>>> implementation-defined. The order of allocation of bit-fields within a unit (high-order to
>>> low-order or low-order to high-order) is implementation-defined. The alignment of the
>>> addressable storage unit is unspecified.
>>
>> In the C++ standard, 9.6p1 says much the same thing, in somewhat less
>> formal language.
> 
> I have the vague memory of someone claiming that C++ allowed for an
> out of order storage of bit-fields, but I would be happy to learn the
> contrary.

You won't be happy. "in-order" has two different possible meanings, and
each implementation has the option of choosing either one. Both C and
C++ are in agreement on this. Different implementations for the same
platform could make different choices (though market forces make that
unlikely); a single implementation could even make it a command-line option.
C++ allows more freedom than C, because it doesn't require consecutive
bit-fields in the same allocation unit to occupy adjacent sets of bits.
That means that there's a lot more than just two different possible orders.

>> Neither standard specifies the size of the allocation unit from which
>> bit-fields are allocated. Which size were you assuming was specified by
>> the standard?
> 
> It must be an addressable storage unit, so it must be a multiple of 8
> bit (I assumed that CHAR_BITS is 8). So what ever multiple of 8 is
> chosen for it c and d will always fit into the same unit. So the order
> will always be a-b-c-d-e or the other way around.

Even in C, there's a lot more than just two possible orders. If, for
example, the allocation unit size is 16, a and b will have to be in the
same allocation unit, and c, d, and e will have to be in the same
allocation unit, but depending upon the allocation order chosen by the
implementation, the fields within each allocation unit could be stored
in either order: "ab cde" or "ba edc". The implementation's definition
of allocation order could even specify different orders in even and odd
numbered words (though I can't think of any reason to do so, except on
middle-endian machines with allocation units of at least 32 bits): "ab
edc" or "ba cde".

Do you still feel that the C standard is sufficiently specific?

0
jameskuyper (5635)
8/28/2012 8:56:57 PM
On 08/28/2012 04:36 PM, Jens Gustedt wrote:
> Am 28.08.2012 20:50, schrieb James Kuyper:
>> On 08/28/2012 12:45 PM, Jens Gustedt wrote:
>>> Am 28.08.2012 17:57, schrieb David Brown:
>>>>> In C this
>>>>>
>>>>> struct {
>>>>>      unsigned a : 8;
>>>>>      unsigned b : 8;
>>>>>      unsigned c : 4;
>>>>>      unsigned d : 4;
>>>>>      unsigned e : 8;
>>>>> }
>>>>>
>>>>> should do what you want, provided CHAR_BITS is 8. Wouldn't that be
>>>>> acceptable for you? I find it even clearer in its intent.
>>>>>
>>>>> (Bitfields are guaranteed to have no padding and uint8_t is pretty
>>>>> useless other than to guarantee that padding property or that its size
>>>>> is 1.)
>>>>>
>>>>
>>>> In practice, this works fine - but the guarantees in the standard are
>>>> weak.  I /use/ bitfields regularly, with different types and enum types
>>>> in the bitfields.  But I would prefer that the standards said that such
>>>> usage was completely well-defined.
>>>
>>> can't agree on that, the standard describes exactly how this has to be
>>> layed out. (well it could decide to pad it to 64 bit, but that's it.)
>>
>> That's not consistent with my understanding of the standard. Could you
>> specify precisely how you thought the standard required that structure
>> to be laid out?
>>
>> The relevant clause from the C standard is 6.7.2.1p11:
>>> An implementation may allocate any addressable storage unit large enough to hold a bitfield.
>>> If enough space remains, a bit-field that immediately follows another bit-field in a
>>> structure shall be packed into adjacent bits of the same unit. If insufficient space remains,
>>> whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is
>>> implementation-defined. The order of allocation of bit-fields within a unit (high-order to
>>> low-order or low-order to high-order) is implementation-defined. The alignment of the
>>> addressable storage unit is unspecified.
>>
>> In the C++ standard, 9.6p1 says much the same thing, in somewhat less
>> formal language.
> 
> I have the vague memory of someone claiming that C++ allowed for an
> out of order storage of bit-fields, but I would be happy to learn the
> contrary.

You won't be happy. "in-order" has two different possible meanings, and
each implementation has the option of choosing either one. Both C and
C++ are in agreement on this. Different implementations for the same
platform could make different choices (though market forces make that
unlikely); a single implementation could even make it a command-line option.
C++ allows more freedom than C, because it doesn't require consecutive
bit-fields in the same allocation unit to occupy adjacent sets of bits.
That means that there's a lot more than just two different possible orders.

>> Neither standard specifies the size of the allocation unit from which
>> bit-fields are allocated. Which size were you assuming was specified by
>> the standard?
> 
> It must be an addressable storage unit, so it must be a multiple of 8
> bit (I assumed that CHAR_BITS is 8). So what ever multiple of 8 is
> chosen for it c and d will always fit into the same unit. So the order
> will always be a-b-c-d-e or the other way around.

Even in C, there's a lot more than just two possible orders. If, for
example, the allocation unit size is 16, a and b will have to be in the
same allocation unit, and c, d, and e will have to be in the same
allocation unit, but depending upon the allocation order chosen by the
implementation, the fields within each allocation unit could be stored
in either order: "ab cde" or "ba edc". The implementation's definition
of allocation order could even specify different orders in even and odd
numbered words (though I can't think of any reason to do so, except on
middle-endian machines with allocation units of at least 32 bits): "ab
edc" or "ba cde".

Do you still feel that the C standard is sufficiently specific?

0
jameskuyper (5635)
8/28/2012 8:58:59 PM
On 08/28/2012 04:47 PM, Jens Gustedt wrote:
....
> Also I think that CHAR_BIT==9 could imply the existence of uint9_t,
> wouldn't it? One could expect that it then has the types that
> correspond to sizeof(int)*CHAR_BIT and similar multiples, no?

It would not be mandatory, but it would be extremely likely.
0
jameskuyper (5635)
8/28/2012 8:59:37 PM
Am 28.08.2012 21:15, schrieb Bo Persson:
> Jens Gustedt wrote 2012-08-28 21:02:
> 
>>
>> You need "void*" when you use "malloc" or other stuff for
>> compatibility with C. So why the hell have it function differently in
>> C++? This is just an inconvenience / annoyance.
>>
> 
> No, it was done on purpose.
> 
> If you write
> 
> MyClass* x = malloc(sizeof(MyClass));
> 
> you are in real trouble, because you forgot to call the constructor of
> MyClass. You really don't want to have that conversion by default.

exactly that was my point. But the problem is not that "malloc" has a
return type of "void*" the problem is the use of "malloc"
itself. Don't shoot the messenger.

In C++, somebody using "malloc" is on his own. Casting to the target
pointer type is even more of a problem, because it is just hiding the
fact that you didn't call a constructor. You got to be very sure of
what you are doing, anyhow.

Requesting that you should cast the "void*" is counterproductive.  A
"strict C++" mode that barks at you for any use of "malloc", *that*
would be appropriate.

I'd still like to hear of a plausible use case for "void*" in C++ that
is not related to C compability or to the overloading of "operator
new".

Jens
0
8/28/2012 9:00:16 PM
On Tue, 28 Aug 2012 23:00:16 +0200
Jens Gustedt <jens.gustedt@loria.fr> wrote:

> 
> I'd still like to hear of a plausible use case for "void*" in C++ that
> is not related to C compability or to the overloading of "operator
> new".
> 
Well, when implementing template container for pointers, it is great
optimization to use just single class specialized for pointers to void,
and cast to appropriate pointer type in specialized classes,
while using single implementation.
It greatly reduces code size.

0
mel2515 (279)
8/28/2012 9:12:08 PM
On 2012-08-28 16:00, Jens Gustedt wrote:
> Am 28.08.2012 21:15, schrieb Bo Persson:
>> Jens Gustedt wrote 2012-08-28 21:02:
>>
>>>
>>> You need "void*" when you use "malloc" or other stuff for
>>> compatibility with C. So why the hell have it function differently in
>>> C++? This is just an inconvenience / annoyance.
>>>
>>
>> No, it was done on purpose.
>>
>> If you write
>>
>> MyClass* x = malloc(sizeof(MyClass));
>>
>> you are in real trouble, because you forgot to call the constructor of
>> MyClass. You really don't want to have that conversion by default.
>
> exactly that was my point. But the problem is not that "malloc" has a
> return type of "void*" the problem is the use of "malloc"
> itself. Don't shoot the messenger.
>
> In C++, somebody using "malloc" is on his own. Casting to the target
> pointer type is even more of a problem, because it is just hiding the
> fact that you didn't call a constructor. You got to be very sure of
> what you are doing, anyhow.
>
> Requesting that you should cast the "void*" is counterproductive.  A
> "strict C++" mode that barks at you for any use of "malloc", *that*
> would be appropriate.

malloc is not the only function - standard or otherwise - that returns a 
void*. Are you suggesting that C++ should forbid malloc, or that C++ 
should forbid void*, or that C++ should have some other type whose only 
purpose is to represent void* returns from C functions?

0
8/28/2012 9:25:45 PM
Am 28.08.2012 22:56, schrieb James Kuyper:
> On 08/28/2012 04:36 PM, Jens Gustedt wrote:

>> I have the vague memory of someone claiming that C++ allowed for an
>> out of order storage of bit-fields, but I would be happy to learn the
>> contrary.
> 
> You won't be happy. "in-order" has two different possible meanings, and
> each implementation has the option of choosing either one. Both C and
> C++ are in agreement on this. Different implementations for the same
> platform could make different choices (though market forces make that
> unlikely); a single implementation could even make it a command-line option.
> C++ allows more freedom than C, because it doesn't require consecutive
> bit-fields in the same allocation unit to occupy adjacent sets of bits.
> That means that there's a lot more than just two different possible orders.

argh

> Even in C, there's a lot more than just two possible orders...

Effectively, I read this phrase

 The order of allocation of bit-fields within a unit (high-order to
 low-order or low-order to high-order) is implementation-defined.

that an implementation would have to choose one of the orderings once
and for all and apply this to all cases consistently.

But it seems that interpreting such text then becomes more a question
of English skills than of anything else.

If in fact, people are interpreting this differently in the sense that
"given storage location X here is an algorithm to determine the
ordering" is sufficient as defintion for an implementation, and so
allowing for a determination of that ordering from location of the
storage unit inside a bigger unit and stuff like that, then

> Do you still feel that the C standard is sufficiently specific?

no

and then it would need more precision. But my English is probably not
good enough to be capable to make a proposal that is better than the
existing text, then.

Jens
0
8/28/2012 9:28:01 PM
On 08/28/2012 05:12 PM, Melzzzzz wrote:
> On Tue, 28 Aug 2012 23:00:16 +0200
> Jens Gustedt <jens.gustedt@loria.fr> wrote:
> 
>>
>> I'd still like to hear of a plausible use case for "void*" in C++ that
>> is not related to C compability or to the overloading of "operator
>> new".
>>
> Well, when implementing template container for pointers, it is great
> optimization to use just single class specialized for pointers to void,
> and cast to appropriate pointer type in specialized classes,
> while using single implementation.
> It greatly reduces code size.

Given that C++ doesn't allow implicit conversions from void*, char* can
be just about as good as void* for that kind of purpose.

0
jameskuyper (5635)
8/28/2012 9:30:27 PM
On Tue, 28 Aug 2012 17:30:27 -0400
James Kuyper <jameskuyper@verizon.net> wrote:

> On 08/28/2012 05:12 PM, Melzzzzz wrote:
> > On Tue, 28 Aug 2012 23:00:16 +0200
> > Jens Gustedt <jens.gustedt@loria.fr> wrote:
> > 
> >>
> >> I'd still like to hear of a plausible use case for "void*" in C++
> >> that is not related to C compability or to the overloading of
> >> "operator new".
> >>
> > Well, when implementing template container for pointers, it is great
> > optimization to use just single class specialized for pointers to
> > void, and cast to appropriate pointer type in specialized classes,
> > while using single implementation.
> > It greatly reduces code size.
> 
> Given that C++ doesn't allow implicit conversions from void*, char*
> can be just about as good as void* for that kind of purpose.
> 

True... Only thing useful is that one don't have to cast when
converting to void*, so it's halfway there ;)


0
mel2515 (279)
8/28/2012 9:38:31 PM
On 8/28/2012 1:58 PM, Bo Persson wrote:
> BGB wrote 2012-08-28 05:34:
>> On 8/27/2012 9:47 PM, Casey Carter wrote:
>>
>>> That implicit conversion from void* to any pointer type is a dangerous
>>> hole in the type system. I admit I'm not much of a C programmer anymore:
>>> the only valid reason I can think of to have this conversion is so that
>>> malloc calls don't require you to specify the type _three_ times (e.g.,
>>> int* p = (int*)malloc(sizeof(*p)); ).
>>>
>>
>> there are plenty of uses besides malloc, so malloc is just one of many
>> cases (mmap, memcpy, VirtualAlloc, ...).
>
> But you don't use memcpy for C++ type, you use std::copy which is typed.
> And you don't do malloc either, you use the containers from the C++
> standard library. Or use the occasional new X, which doesn't need a cast
> either.
>

yes, but the topic here would be C code running in a C++ compiler, in 
such a scenario where plain C in a C++ compiler worked the same as in a 
C compiler.

expecting the code to be rewritten into C++ in the process is a no-go.


>>
>> or, a biggie:
>> for any user-defined code which accepts or returns "void *".
>
> No, these can be templates and accept or return T*, for any type T.
>

not in C code.


>>
>> for example, to do similar tasks in C++ often requires a larger number
>> of casts.
>
> If you do it the C++ way, it actually uses fewer casts.  :-)
>
>
> A big problem with trying to finds the common ground between C and C++
> is that lots of good C++ code isn't using many C features at all. And
> well written C code tend to be very non-idiomatic C++ code.
>

but, more importantly though:
existing C code has to still work, if the languages were to be merged.

idiomatic or not, things still working is the main thing.

yes, it is possible to just write in the "least-common-denominator" of C 
and C++ (I have done this a few times), but this is not the issue here.


0
cr88192355 (1928)
8/28/2012 9:55:24 PM
Am 28.08.2012 23:25, schrieb Casey Carter:
> On 2012-08-28 16:00, Jens Gustedt wrote:
>> Requesting that you should cast the "void*" is counterproductive.  A
>> "strict C++" mode that barks at you for any use of "malloc", *that*
>> would be appropriate.
> 
> malloc is not the only function - standard or otherwise - that returns a
> void*.

In the C11 standard I found:

void *aligned_alloc(size_t alignment, size_t size);
void *calloc(size_t nmemb, size_t size);
void *malloc(size_t size);
void *realloc(void *ptr, size_t size);
void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
void *memmove(void *s1, const void *s2, size_t n);
void *memchr(const void *s, int c, size_t n);
void *memset(void *s, int c, size_t n);

void *bsearch(const void *key, const void *base,
              size_t nmemb, size_t size,
              int (*compar)(const void *, const void *));

void *bsearch_s(const void *key, const void *base,
                rsize_t nmemb, rsize_t size,
                int (*compar)(const void *k, const void *y, void *context),
                void *context);

void *tss_get(tss_t key);

Maybe I overlooked something, possible, but these are not really a
lot, and nothing which would be considered good style to be used in
C++, I think.

> Are you suggesting that C++ should forbid malloc, or that C++
> should forbid void*, or that C++ should have some other type whose only
> purpose is to represent void* returns from C functions?

That it'd leave "void*" alone and uses it as it was originally defined
in C. It just makes no sense. Somebody that uses C memory functions is
beyond the red line anyhow. Requiring a cast here is just useless, and
is not adding to compability, but the contrary.

Use "unsigned char*" instead, when you feel the need of an untyped
pointer inside C++, which should be rare in C++, anyhow.

Jens
0
8/28/2012 9:58:23 PM
On 28/08/2012 22:58, Jens Gustedt wrote:
> Am 28.08.2012 23:25, schrieb Casey Carter:
>> Are you suggesting that C++ should forbid malloc, or that C++
>> should forbid void*, or that C++ should have some other type whose only
>> purpose is to represent void* returns from C functions?
>
> That it'd leave "void*" alone and uses it as it was originally defined
> in C. It just makes no sense. Somebody that uses C memory functions is
> beyond the red line anyhow. Requiring a cast here is just useless, and
> is not adding to compability, but the contrary.
>
> Use "unsigned char*" instead, when you feel the need of an untyped
> pointer inside C++, which should be rare in C++, anyhow.

What utter nonsense mate.  Use void* not unsigned char* for untyped 
pointers in C++.

/Leigh

0
leigh (1128)
8/28/2012 10:03:34 PM
Am 28.08.2012 20:38, schrieb Bo Persson:
> Jens Gustedt wrote 2012-08-27 18:34:
> 
>> I am not sure that I understand this one. C has the optional uintXX_t
>> that are guaranteed to have a fixed width no padding etc, if they
>> exist. Would it for your purpose just suffice to make some of these
>> types mandatory e.g for 8, 16, 32 and 64 bit integers?
>>
> 
> Why would you want to make this mandatory for everyone? Why not be
> satisfied if your code is portable to systems having these types?

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?

Jens


0
8/28/2012 10:07:57 PM
On 08/28/2012 05:28 PM, Jens Gustedt wrote:
> Am 28.08.2012 22:56, schrieb James Kuyper:
>> On 08/28/2012 04:36 PM, Jens Gustedt wrote:
> 
>>> I have the vague memory of someone claiming that C++ allowed for an
>>> out of order storage of bit-fields, but I would be happy to learn the
>>> contrary.
>>
>> You won't be happy. "in-order" has two different possible meanings, and
>> each implementation has the option of choosing either one. Both C and
>> C++ are in agreement on this. Different implementations for the same
>> platform could make different choices (though market forces make that
>> unlikely); a single implementation could even make it a command-line option.
>> C++ allows more freedom than C, because it doesn't require consecutive
>> bit-fields in the same allocation unit to occupy adjacent sets of bits.
>> That means that there's a lot more than just two different possible orders.
> 
> argh
> 
>> Even in C, there's a lot more than just two possible orders...

Sorry, that was an editing error. The previous comment was the correct
one: "C++ ... [allows] a lot more than two different possible orders"

> Effectively, I read this phrase
> 
>  The order of allocation of bit-fields within a unit (high-order to
>  low-order or low-order to high-order) is implementation-defined.
> 
> that an implementation would have to choose one of the orderings once
> and for all and apply this to all cases consistently.

That's correct. The comment was actually intended to be about C++, not
C. The text in the C++ standard that comes closest to saying the same
thing merely gives "left-to-right" and "right-to-left" (sic) as examples
of orders that actually occur, without specifying that they are the only
permitted orders.

>> Do you still feel that the C standard is sufficiently specific?
> 
> no
> 
> and then it would need more precision. But my English is probably not
> good enough to be capable to make a proposal that is better than the
> existing text, then.

It would be a trivial exercise to rewrite this to remove almost all of
the freedom implementations currently have in laying out bit fields. It
wouldn't require particularly good English skills:

Specify that plain 'int' is signed in bit fields, just as it is
everywhere else. Specify the size of the allocation unit. Specify 2's
complement representation for signed integer types. Prohibit
representations that have padding bits or allow trap representations.
Mandate big-endian order (or little endian order - but don't allow both
- don't give implementations a choice) prohibiting all other orders.
Specify that bits are assigned to bit-fields in order from high-order
bits to low-order bits (or vice-versa - but pick one as allowed by the
standard, and prohibit the other). Continue to require, as C already
does, but C++ does not, that consecutive bit-fields within the same
allocation unit be allocated adjacent sets of bits. Either mandate or
prohibit bit-fields that cross allocation unit boundaries - but choose one.

The hard part would not be writing up such a change, but getting it
approved. It would make bit-fields much more portable, at the cost of
breaking huge quantities of existing code when it tries to read data
written using a different lay-out, or tries to communicate with existing
routines (many of them not written in C) that use a different lay-out.
0
jameskuyper (5635)
8/28/2012 10:18:04 PM
On 2012-08-28, Casey Carter <casey_at_carter_dot_net@nospam.invalid> wrote:
> There's no such thing as 'extern "C" code': extern "foo" is a *linkage 
> specification* whose sole purpose is to tell the implementation to 
> engage the ABI machinery appropriate for language "foo".

For one thing, 'extern "C"' may turn off C++ name mangling.
0
ike7 (214)
8/28/2012 10:47:06 PM
On Wednesday, August 29, 2012 1:18:07 AM UTC+3, James Kuyper wrote:
> Specify that plain 'int' is signed in bit fields, just as it is
> everywhere else. Specify the size of the allocation unit. Specify 2's
> complement representation for signed integer types. Prohibit
> representations that have padding bits or allow trap representations.
> Mandate big-endian order (or little endian order - but don't allow both
> - don't give implementations a choice) prohibiting all other orders.
> Specify that bits are assigned to bit-fields in order from high-order
> bits to low-order bits (or vice-versa - but pick one as allowed by the
> standard, and prohibit the other). Continue to require, as C already
> does, but C++ does not, that consecutive bit-fields within the same
> allocation unit be allocated adjacent sets of bits. Either mandate or
> prohibit bit-fields that cross allocation unit boundaries - but choose one.

Why it is needed and what it helps? Two platforms do not operate
on same memory. When two platforms communicate then there is
either some protocol or file format involved. So it is up to the
protocol or file format specification to specify the bits not up
to C or C++ standards. 

To keep things internally in memory bit-by bit like in some protocol
or file format would be terribly inefficient.
0
ootiib (965)
8/28/2012 10:56:28 PM
On 08/28/2012 06:18 PM, James Kuyper wrote:
> On 08/28/2012 05:28 PM, Jens Gustedt wrote:
>> Am 28.08.2012 22:56, schrieb James Kuyper:
....
>>> Even in C, there's a lot more than just two possible orders...
> 
> Sorry, that was an editing error. The previous comment was the correct
> one: "C++ ... [allows] a lot more than two different possible orders"

When I wrote that reply , I couldn't easily see my previous message,
only the part that you had quoted. I assumed that I'd left a stupid
editing error in my message. That assumption was incorrect.

>> Effectively, I read this phrase
>>
>>  The order of allocation of bit-fields within a unit (high-order to
>>  low-order or low-order to high-order) is implementation-defined.
>>
>> that an implementation would have to choose one of the orderings once
>> and for all and apply this to all cases consistently.

My comment was in fact perfectly correct. The key point that you missed
was that the order is specified only "within a unit", not "across
units". If the unit is 16 bits long, then "a" and "b" must both be in
the first allocation unit, and "c", "d", and "e" must be in the second
allocation unit, but "a" could occupy either the first byte or the
second byte of the first unit, and "e" could occupy either the first
byte or the second byte of the second unit. There's no good reason for
an implementation to make inconsistent choices in the two units, but
it's not required to make consistent ones, either. "ab cde" and "ba ecd"
are plausible possibilities, "ab ecd" and "ba cde" are implausible but
permitted possibilities, while (assuming 16-bit allocation units) "edc
ba" is NOT a possibility. With 32-bit allocation units, "edcba" is a
possibility.


0
jameskuyper (5635)
8/28/2012 11:01:54 PM
On 08/28/2012 06:56 PM, �� Tiib wrote:
> On Wednesday, August 29, 2012 1:18:07 AM UTC+3, James Kuyper wrote:
>> Specify that plain 'int' is signed in bit fields, just as it is
>> everywhere else. Specify the size of the allocation unit. Specify 2's
>> complement representation for signed integer types. Prohibit
>> representations that have padding bits or allow trap representations.
>> Mandate big-endian order (or little endian order - but don't allow both
>> - don't give implementations a choice) prohibiting all other orders.
>> Specify that bits are assigned to bit-fields in order from high-order
>> bits to low-order bits (or vice-versa - but pick one as allowed by the
>> standard, and prohibit the other). Continue to require, as C already
>> does, but C++ does not, that consecutive bit-fields within the same
>> allocation unit be allocated adjacent sets of bits. Either mandate or
>> prohibit bit-fields that cross allocation unit boundaries - but choose one.
> 
> Why it is needed and what it helps? Two platforms do not operate
> on same memory. When two platforms communicate then there is
> either some protocol or file format involved. So it is up to the
> protocol or file format specification to specify the bits not up
> to C or C++ standards. 

With the above changes (and a few additional ones I didn't bother to
specify), there could be a struct definition that uniquely corresponds
to any given protocol or file format, making reading and writing such
files, or parsing/writing such protocols, a lot easier. With the
language as currently written, structs are useless for portable code of
that kind, only bit-wise operations on arrays of unsigned char can be
used (even that breaks down if CHAR_BIT != 8, but that's rather uncommon).

> To keep things internally in memory bit-by bit like in some protocol
> or file format would be terribly inefficient.

You can always read it into a bit-packed struct, and then unpack it into
a more efficient structure. The code would still be a lot simpler than
what I currently have to write.

0
jameskuyper (5635)
8/28/2012 11:09:55 PM
Jens Gustedt <jens.gustedt@loria.fr> writes:
[...]
> Also I think that CHAR_BIT==9 could imply the existence of uint9_t,
> wouldn't it? One could expect that it then has the types that
> correspond to sizeof(int)*CHAR_BIT and similar multiples, no?

The standard makes {,u}int{8,16,32,64}_t mandatory if the
implementation provides types that meet the requirements.  All other
such types are optional.  A system with CHAR_BIT==9 would *probably*
provide uint9_t, but the C standard doesn't require it to.  I suppose
the same applies to C++ as of the 2011 standard.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
8/29/2012 12:07:50 AM
Casey Carter=E6=96=BC 2012=E5=B9=B48=E6=9C=8829=E6=97=A5=E6=98=9F=E6=9C=9F=
=E4=B8=89UTC+8=E4=B8=8A=E5=8D=881=E6=99=8218=E5=88=8635=E7=A7=92=E5=AF=AB=
=E9=81=93=EF=BC=9A
> On 2012-08-27 22:34, BGB wrote:
>=20
> >> Definition of NULL as ((void*)0) is contingent on the implicit
>=20
> >> conversion of void* to other pointer types.
>=20
> >>
>=20
> >
>=20
> > well, yes, but I listed that they could add this as well.
>=20
> > probably most C++ code wouldn't notice the change.
>=20
>=20
>=20
> I should have been more clear about my point here: I was trying to say=20
>=20
> that the only reason this definition of NULL is unacceptable to C++ is=20
>=20
> because of the lack of the implicit conversion from void*. Given that=20
>=20
> conversion, there would be no other barrier in C++ to using ((void*)0)=20
>=20
> for NULL.
>=20
>=20
>=20
> > possibly, the change could be limited to 'extern "C"' code or similar
>=20
> > (and/or could be ignored in cases of templates or overloading, or at
>=20
> > least be a lower priority than any other matches).
>=20
>=20
>=20
> I think the rules for overload resolution and template type deduction=20
>=20
> are complicated enough without introducing a feature that behaves=20
>=20
> differently depending on whether or not it interacts with those systems.
>=20
>=20
>=20
> There's no such thing as 'extern "C" code': extern "foo" is a *linkage=20
>=20
> specification* whose sole purpose is to tell the implementation to=20
>=20
> engage the ABI machinery appropriate for language "foo".
>=20
>=20
>=20
> >> That implicit conversion from void* to any pointer type is a dangerous
>=20
> >> hole in the type system. I admit I'm not much of a C programmer anymor=
e:
>=20
> >> the only valid reason I can think of to have this conversion is so tha=
t
>=20
> >> malloc calls don't require you to specify the type _three_ times (e.g.=
,
>=20
> >> int* p =3D (int*)malloc(sizeof(*p)); ).
>=20
> >>
>=20
> >
>=20
> > there are plenty of uses besides malloc, so malloc is just one of many
>=20
> > cases (mmap, memcpy, VirtualAlloc, ...).
>=20
> >
>=20
> > or, a biggie:
>=20
> > for any user-defined code which accepts or returns "void *".
>=20
>=20
>=20
> Returns, not accepts. The implicit conversion _from_ void* is dangerous,=
=20
>=20
> implicit conversion _to_ void* is perfectly safe type erasure.
>=20
>=20
>=20
> >
>=20
> > for example, to do similar tasks in C++ often requires a larger number
>=20
> > of casts.
>=20
> >
>=20
> >
>=20
> >> If I really wanted to pitch the committees for stronger ties between C
>=20
> >> and C++, I'd probably suggest that (a) C pick up nullptr (and nullptr_=
t)
>=20
> >> to serve as generic null pointer constant,
>=20
> >
>=20
> > could work...
>=20
> >
>=20
> >
>=20
> >> (b) C drop the implicit
>=20
> >> conversion from void*,
>=20
> >
>=20
> > this would break large amounts of C code.
>=20
>=20
>=20
> I'll handwave here and claim that's what compiler options are for. Valid=
=20
>=20
> C90 code will always be valid C90 code, I see no reason why a future C20=
=20
>=20
> compiler couldn't be instructed to compile code as C90. Old code will=20
>=20
> always be old code, but does that mean that we have to keep on writing=20
>=20
> old code forever?
>=20
>=20
>=20
> It's already the case that C11 made some C99 features optional: there=20
>=20
> may be conforming C11 compilers that refuse to compile some conforming=20
>=20
> C99 programs. The kind of change I suggest is quantitatively but not=20
>=20
> qualitatively different.
>=20
>=20
>=20
> > I don't think people on either side would want changes which cause thei=
r
>=20
> > existing programs to break and have to be rewritten.
>=20
> >
>=20
> >> and (c) both languages use a new distinct type
>=20
> >> that can implicitly convert to any pointer type.
>=20
> >
>=20
> > we call this 'void *', where this is nearly the only thing that can
>=20
> > really be done with this type anyways ("void" variables are otherwise
>=20
> > pretty much useless, ...).
>=20
>=20
>=20
> I am differentiating between the implicit conversion _from_ any pointer=
=20
>=20
> type and the implicit conversion _to_ any pointer type; I posit that=20
>=20
> those two features have unique design intentions and should therefore be=
=20
>=20
> represented by distinct types. C conflates the two ideas in void*, C++=20
>=20
> doesn't have the conversion _to_ any pointer type at all, except for=20
>=20
> nullptr. (Given how simple it is to make a user-defined type in C++ that=
=20
>=20
> implicitly converts to any pointer type, it's notable that I've never=20
>=20
> seen anyone feel the need to do so.)
>=20
>=20
>=20
> void* has 2 uses in C:
>=20
> 1. it's the "sink" type to which all other pointer types can be=20
>=20
> implicitly converted.
>=20
> 2. it's the "source" type that implicitly converts to all other pointer=
=20
>=20
> types.
>=20
>=20
>=20
> and 2 uses in C++:
>=20
> 1. "sink" type just as in C.
>=20
> 2. type-erased pointer that designates _some_kind_ of object about which=
=20
>=20
> nothing is known except its location in memory.
>=20
>=20
>=20
> The secondary usage is diametrically opposite between C and C++: one=20
>=20
> disallows using a void* for any purpose without a cast, the other allows=
=20
>=20
> you to pass a void* where you would any pointer type without a cast. In=
=20
>=20
> C, I can pass the same void* to fclose, free, strcat, and=20
>=20
> hundreds/thousands of other functions without a compiler diagnostic.=20
>=20
> Using void* you've effectively opted out of a large part of the type syst=
em.
>=20
>=20
>=20
> C programmers also often use void* as either a type-erased or generic=20
>=20
> pointer but do so purely based on convention and discipline: you will=20
>=20
> get no help from the compiler. If an intern jumps into your code the=20
>=20
> next day and passes your type-erased pointer to fputs, the compiler will=
=20
>=20
> accept it happily.
>=20
>=20
>=20
> >  > Holes in the type
>=20
> >> system are very useful at the fringes of C/C++ programs, I think that
>=20
> >> having distinct "source" (X -> any*) and "sink" (any* -> X) pointer
>=20
> >> types preserves the utility of C-style void* while minimizing the dang=
er.
>=20
> >
>=20
> > yes, but the least impact route would be to just pick up C's "void *"
>=20
> > semantics for this, since C++ code isn't likely to notice, and existing
>=20
> > C code can keep working unmodified.
>=20
>=20
>=20
> While it's true that making the language more permissive doesn't impact=
=20
>=20
> the correctness of existing programs, that doesn't necessarily make it=20
>=20
> always a good idea. I seriously doubt that the C++ community would ever=
=20
>=20
> accept implicit conversion from void* into the language; the case I'm=20
>=20
> attempting to make here is that C shouldn't have that feature either and=
=20
>=20
> likely would not if it was designed afresh today.
>=20
>=20
>=20
> Given that preserving the semantics of old code has a higher priority to=
=20
>=20
> the C community than almost any other concern, I think it's unlikely=20
>=20
> that we will ever have a C++ that is truly a superset of C.  If anything=
=20
>=20
> I think it's more likely that C++ would introduce even more breaking=20
>=20
> changes to become _less_ compatible with C.

Please check objective C. Programmers will pick the right tool=20
at the right time for their tasks to earn money in the industry.
0
8/29/2012 2:32:53 AM
Am 29.08.2012 00:03, schrieb Leigh Johnston:
> On 28/08/2012 22:58, Jens Gustedt wrote:
>> Am 28.08.2012 23:25, schrieb Casey Carter:
>>> Are you suggesting that C++ should forbid malloc, or that C++
>>> should forbid void*, or that C++ should have some other type whose only
>>> purpose is to represent void* returns from C functions?
>>
>> That it'd leave "void*" alone and uses it as it was originally defined
>> in C. It just makes no sense. Somebody that uses C memory functions is
>> beyond the red line anyhow. Requiring a cast here is just useless, and
>> is not adding to compability, but the contrary.
>>
>> Use "unsigned char*" instead, when you feel the need of an untyped
>> pointer inside C++, which should be rare in C++, anyhow.
> 
> What utter nonsense mate.

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").

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

>  Use void* not unsigned char* for untyped pointers in C++.

What higher entity revealed you that commandment?

Jens
0
8/29/2012 6:02:20 AM
On 28/08/2012 18:45, Jens Gustedt wrote:
> Am 28.08.2012 17:57, schrieb David Brown:
>>> In C this
>>>
>>> struct {
>>>       unsigned a : 8;
>>>       unsigned b : 8;
>>>       unsigned c : 4;
>>>       unsigned d : 4;
>>>       unsigned e : 8;
>>> }
>>>
>>> should do what you want, provided CHAR_BITS is 8. Wouldn't that be
>>> acceptable for you? I find it even clearer in its intent.
>>>
>>> (Bitfields are guaranteed to have no padding and uint8_t is pretty
>>> useless other than to guarantee that padding property or that its size
>>> is 1.)
>>>
>>
>> In practice, this works fine - but the guarantees in the standard are
>> weak.  I /use/ bitfields regularly, with different types and enum types
>> in the bitfields.  But I would prefer that the standards said that such
>> usage was completely well-defined.
>
> can't agree on that, the standard describes exactly how this has to be
> layed out. (well it could decide to pad it to 64 bit, but that's it.)
>

I am beginning to suspect that the bitfields are a little better 
specified than I had thought... but I still see problems.

The big unspecified issue is the ordering of the bitfields, as shown by 
another poster, which is often different according to the endianness of 
the target.  It can also vary between compilers for the same target, and 
even between compiler versions on the same target (it changed between 
two versions of MS' C compiler on x86).  The standards say it is 
"implementation dependent", which is a real problem if you want to use 
bitfields for hardware register access, or within communication 
protocols, filesystems, file formats, etc.

(I am assuming 8-bit char here, though I occasionally have to deal with 
targets with 16-bit or even 32-bit char - these are typically DSP's, and 
they are typically hideous to work with anyway.)

Back to the padding, alignment, etc.  I gather you are correct that the 
standards guarantees that no padding is added as long as the fields fit 
within the space.  But there are a few points I find problematic (I am 
referring here to the C99 standards, document WG14/N1256 of September 
2007).  In section 6.7.2.1 "Structure and union specifiers", we have:

4. "Abit-field shall have a type that is a qualified or unqualified 
version of _Bool, signed int, unsigned int,orsome other 
implementation-defined type."

Most compilers I have used allow different types, but it is 
implementation dependent.  In particular, if I want an 8-bit struct 
consisting of bitfields, I will normally use bitfields of type 
"uint8_t".  Using "unsigned int" is likely to make the whole struct 
16-bit or 32-bit, depending on sizeof(int).  I don't see why this is not 
specified exactly (I believe the use of other bitfield types /is/ 
specified in C++, but I haven't read the standards).

10. "An implementation may allocate anyaddressable storage unit large 
enough to hold a bit-field. If enough space remains, a bit-field that 
immediately follows another bit-field in a structure shall be packed 
into adjacent bits of the same unit. If insufficient space remains,
whether a bit-field that does not fit is put into the next unit or 
overlaps adjacent units is implementation-defined. The order of 
allocation of bit-fields within a unit (high-order to low-order or 
low-order to high-order) is implementation-defined. The alignment of the
addressable storage unit is unspecified."

That's a lot of "unspecified" and "implementation-defined" !  The size 
of bitfield container units, and their alignment, is not specified.  It 
is not even guaranteed to be the same alignment as is otherwise used for 
that type (which is also implementation dependent).



The sizes of the "units" are not specified, which means that the whole 
bitfield can have different sizes according to target.  This could be 
particularly bad if you have a bitfield ordering that does not match the 
endianness - simply be choosing different unit sizes, the compiler could 
make significantly different layouts.  (I can't think off-hand of 
targets that have this mixture, but it is certainly legal - and may 
perhaps be used on targets such as the PPC in little-endian mode.)

And if you throw "volatile" into the mix - as you might well do for 
hardware register access - it gets even worse.  The size of "unit" used 
to access the hardware can be critically important.  Recent versions of 
gcc make this explicit - the field will be accessed using a data size to 
match the underlying type used in the bitfield.  But that is just one 
compiler - it is not in the standards.

mvh.,

David





0
david2384 (2168)
8/29/2012 7:25:15 AM
On 28/08/2012 18:39, James Kuyper wrote:
> On 08/28/2012 09:32 AM, David Brown wrote:
> ...
>> Ultimately, I'd like some way to tell the compiler what data, pointers
>> and/or types can alias what.
>
> If you put two types in a union, within the scope of that union
> declaration a conforming implementation must take aliasing between those
> two types into consideration any time it's dealing with pointers that
> could be pointing at different members of the same union object.
>

Correct me if I'm wrong, but I believe this is actually just an 
"unwritten rule" that all compilers have agreed to follow.  If you make 
a union of two types (say, a "float" and a "uint32_t"), then the 
compiler must put the two entries in the same space, and the programmer 
may access either field.  But if the program writes to one field, then 
reads to the other field are undefined according to the standards.  The 
compiler can therefore ignore aliasing issues, and even ignore the data 
completely, if it sees this situation.  Type-punning unions only work 
because all compiler vendors make it work - not because the standards 
say so.

Section 6.2.6.1 "Representations of types", C99:

7. When a value is stored in a member of an object of union type, the 
bytes of the object representation that do not correspond to that member 
but do correspond to other members takeunspecified values.

A special exception is made if the members of the union are structs 
which contain compatible types at the start - then accessing the common 
initial parts of the structs is legal.

> This won't help you, of course, if you want it to consider aliasing in
> contexts where it's impossible that they refer to the same union object.
>

That's the real problem.

0
david2384 (2168)
8/29/2012 7:41:02 AM
On 28/08/2012 19:14, �� Tiib wrote:
> On Tuesday, August 28, 2012 4:32:56 PM UTC+3, David Brown wrote:
>> well-defined, portable and cross-platform way.  For example, I want to
>> be able to write:
>>
>> struct {
>> 	uint8_t a;
>> 	uint8_t b;
>> 	uint8_t c : 4;
>> 	uint8_t d : 4;
>> 	uint8_t e;
>> }
>
> It is unlikely that C++ will allow nameless structs and unions ever again.
>

In real-world code, I'd have names, so that's no problem.

>> I want to be guaranteed that this struct takes 32 bits, and is aligned
>> to 8-bit boundaries.
>
> static_assert about sizeof guarantees that it won't compile. For bit order
> and padding you need bit more complex static asserts.
>

Yes, I use static_assert to check all these things.  Once I get to use 
newer C (or C++) standards with real static_assert, I'll be happy.  At 
the moment, I use macros that end up causing errors (arrays with 
negative sizes) on assertion failures - they are messy, and give weird 
error messages if they are triggered, but they are a great help anyway.

> As about keywords like 'restrict', 'inline' or 'register' i am sure
 > that on general case compiler and/or linker can optimize lot better
> thanaverage Joe and so the keywords just add pointless bloat.
>

For "register", then I agree entirely - it's only real use now is very 
specialised cases when you want to fix data into a specific register for 
use in assembly.

But it will be a long time before compiler technology can figure out all 
cases of "restrict" by itself - that requires insight between different 
compile units, and hefty analysis on the way the functions are used.

Similarly with "inline" - the compiler can figure out many functions 
that should be inlined, but certainly not all.  There are plenty of 
situations when the programmer knows that inlining a function will be 
very efficient (perhaps due to constant folding), but the compiler 
thinks the function is too large.  Compilers are getting better at this 
(at least, gcc is), but they are not yet omnipotent.  And there are 
situations where the programmer might want to disable automatic inlining 
(to make debugging easier), but still want some functions inlined - 
using the keyword explicitly gives that control.

Perhaps I don't count as an "average Joe"...

0
david2384 (2168)
8/29/2012 7:51:13 AM
Am 29.08.2012 09:41, schrieb David Brown:
> On 28/08/2012 18:39, James Kuyper wrote:
>> On 08/28/2012 09:32 AM, David Brown wrote:
>> ...
>>> Ultimately, I'd like some way to tell the compiler what data, pointers
>>> and/or types can alias what.
>>
>> If you put two types in a union, within the scope of that union
>> declaration a conforming implementation must take aliasing between those
>> two types into consideration any time it's dealing with pointers that
>> could be pointing at different members of the same union object.
>>
> 
> Correct me if I'm wrong, but I believe this is actually just an
> "unwritten rule" that all compilers have agreed to follow.  If you make
> a union of two types (say, a "float" and a "uint32_t"), then the
> compiler must put the two entries in the same space, and the programmer
> may access either field.  But if the program writes to one field, then
> reads to the other field are undefined according to the standards.  The
> compiler can therefore ignore aliasing issues, and even ignore the data
> completely, if it sees this situation.  Type-punning unions only work
> because all compiler vendors make it work - not because the standards
> say so.

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.

So if you happen to have a platform that implements uint32_t (or
another type that has not trap and no padding) it is always safe to
use a union that overlays your data with such a beast or even an array
of these. You'd just have to be careful when interpreting this data,
but it is not UB as such.

AFAIK C++ stayed with the original wording, and so now the
interpretation of union is different in both languages. Basically the
only use of union in C++ would be to save storage in low level
implementations. (real highlevel C++ has completely different means to
achieve that.)

The main intent of unions in C, namely type-punning, isn't guaranteed
in C++.

Jens
0
8/29/2012 8:19:21 AM
Am 29.08.2012 09:51, schrieb David Brown:
> On 28/08/2012 19:14, �� Tiib wrote:

> Yes, I use static_assert to check all these things.  Once I get to use
> newer C (or C++) standards with real static_assert, I'll be happy.  At
> the moment, I use macros that end up causing errors (arrays with
> negative sizes) on assertion failures - they are messy, and give weird
> error messages if they are triggered, but they are a great help anyway.
> 
>> As about keywords like 'restrict', 'inline' or 'register' i am sure
>> that on general case compiler and/or linker can optimize lot better
>> thanaverage Joe and so the keywords just add pointless bloat.

I disagree with all of these points.

> For "register", then I agree entirely - it's only real use now is very
> specialised cases when you want to fix data into a specific register for
> use in assembly.

No, register is a contract that the programmer signs. He promises to
never take the address of that particular object. Whether or not the
compiler uses this is another point, but he may put it in a veritable
'register' or into an immediate optimize it completely out or whatever
pleases. And he *must* issue a diagnostic whenever an attempt is made
to take the address of that object.

As such "register" is nowadays a misnomer, since it doesn't have much
to do with hardware registers of the platform. It still serves a
purpose, and actually it could serve much more if it also would be
allowed in file scope for const qualified objects.

> But it will be a long time before compiler technology can figure out all
> cases of "restrict" by itself - that requires insight between different
> compile units, and hefty analysis on the way the functions are used.

This will never come, because the compiler simply can't
know. "restrict" is an interface specification that assures the called
function that this particular pointer doesn't alias. This is an
invariant that has to be checked at the calling side and relied upon
on the called side. There is no general way to infer this at compile
time if calling function and called function are compiled separately.

> Similarly with "inline" - the compiler can figure out many functions
> that should be inlined, but certainly not all.  There are plenty of
> situations when the programmer knows that inlining a function will be
> very efficient (perhaps due to constant folding), but the compiler
> thinks the function is too large.  Compilers are getting better at this
> (at least, gcc is), but they are not yet omnipotent.  And there are
> situations where the programmer might want to disable automatic inlining
> (to make debugging easier), but still want some functions inlined -
> using the keyword explicitly gives that control.

In C, "inline" is the only possibility to expose the definition of a
function in a header file and not having it implemented repeatedly in
every compilation unit (a static function would do that.)

Here again, if the compiler will really inline your function or not is
subject to a lot of parameters, but you shouldn't care much about
that: you did your best and exposed the definition to every
compilation unit. And again, the name "inline" by itself is perhaps a
misnomer, "dontProduceMultipleSymbolErrors" would have been
a bit more verbose :)

Jens
0
8/29/2012 8:41:07 AM
On 29/08/2012 10:19, Jens Gustedt wrote:
> Am 29.08.2012 09:41, schrieb David Brown:
>> On 28/08/2012 18:39, James Kuyper wrote:
>>> On 08/28/2012 09:32 AM, David Brown wrote:
>>> ...
>>>> Ultimately, I'd like some way to tell the compiler what data, pointers
>>>> and/or types can alias what.
>>>
>>> If you put two types in a union, within the scope of that union
>>> declaration a conforming implementation must take aliasing between those
>>> two types into consideration any time it's dealing with pointers that
>>> could be pointing at different members of the same union object.
>>>
>>
>> Correct me if I'm wrong, but I believe this is actually just an
>> "unwritten rule" that all compilers have agreed to follow.  If you make
>> a union of two types (say, a "float" and a "uint32_t"), then the
>> compiler must put the two entries in the same space, and the programmer
>> may access either field.  But if the program writes to one field, then
>> reads to the other field are undefined according to the standards.  The
>> compiler can therefore ignore aliasing issues, and even ignore the data
>> completely, if it sees this situation.  Type-punning unions only work
>> because all compiler vendors make it work - not because the standards
>> say so.
>
> 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.

The great thing about standards is that there are so many to choose from!

>
> 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.
>

It sounds very much like someone wrote down the "unwritten rule", which 
was nice of them.

> So if you happen to have a platform that implements uint32_t (or
> another type that has not trap and no padding) it is always safe to
> use a union that overlays your data with such a beast or even an array
> of these. You'd just have to be careful when interpreting this data,
> but it is not UB as such.
>
> AFAIK C++ stayed with the original wording, and so now the
> interpretation of union is different in both languages. Basically the
> only use of union in C++ would be to save storage in low level
> implementations. (real highlevel C++ has completely different means to
> achieve that.)
>
> The main intent of unions in C, namely type-punning, isn't guaranteed
> in C++.

I don't know that type-punning was the "main intent" of unions - I think 
saving storage space was the main motivation.  Type-punning just became 
a popular use of it, and has been even more important since alias 
analysis has broken older methods of type-punning.  This is backed up by 
the fact that unions for saving space have been around as long as C, but 
type-punning unions have only been officially supported since a 
correction to C99.

I guess with C++, the "correct" way to handle type-punning is with 
static_cast.  I don't know whether this guarantees the same alias-safe 
characteristics as a type-punning union in C.

>
> Jens
>

0
david2384 (2168)
8/29/2012 8:44:13 AM
Am 29.08.2012 10:44, schrieb David Brown:
> On 29/08/2012 10:19, Jens Gustedt wrote:
> The great thing about standards is that there are so many to choose from!

:)

> I don't know that type-punning was the "main intent" of unions - I think
> saving storage space was the main motivation.

I was perhaps pushing a bit too far, but type punning has been around
since the beginning. And if I understand it right it was the idea of
the committee to affirm that it always had been an intented use case,
and that just the wording in the standard had been too ambiguous.

>  Type-punning just became
> a popular use of it, and has been even more important since alias
> analysis has broken older methods of type-punning.  This is backed up by
> the fact that unions for saving space have been around as long as C, but
> type-punning unions have only been officially supported since a
> correction to C99.

The most prominent use case of type-puning is the network layer in
POSIX and probably all its predecessors. It is really there since the
beginning.

> I guess with C++, the "correct" way to handle type-punning is with
> static_cast.  I don't know whether this guarantees the same alias-safe
> characteristics as a type-punning union in C.

No, I don't think that static_cast will do. Probably reinterpret_cast
would be better. But I am not sure that I personally would be capable
to come up with code that is strictly conforming to C++ and that would
deal with the socket layer correctly.

Jens
0
8/29/2012 10:24:18 AM
On 29/08/2012 10:41, Jens Gustedt wrote:
> Am 29.08.2012 09:51, schrieb David Brown:
>> On 28/08/2012 19:14, �� Tiib wrote:
>
>> Yes, I use static_assert to check all these things.  Once I get to use
>> newer C (or C++) standards with real static_assert, I'll be happy.  At
>> the moment, I use macros that end up causing errors (arrays with
>> negative sizes) on assertion failures - they are messy, and give weird
>> error messages if they are triggered, but they are a great help anyway.
>>
>>> As about keywords like 'restrict', 'inline' or 'register' i am sure
>>> that on general case compiler and/or linker can optimize lot better
>>> thanaverage Joe and so the keywords just add pointless bloat.
>
> I disagree with all of these points.
>
>> For "register", then I agree entirely - it's only real use now is very
>> specialised cases when you want to fix data into a specific register for
>> use in assembly.
>
> No, register is a contract that the programmer signs. He promises to
> never take the address of that particular object. Whether or not the
> compiler uses this is another point, but he may put it in a veritable
> 'register' or into an immediate optimize it completely out or whatever
> pleases. And he *must* issue a diagnostic whenever an attempt is made
> to take the address of that object.
>
> As such "register" is nowadays a misnomer, since it doesn't have much
> to do with hardware registers of the platform. It still serves a
> purpose, and actually it could serve much more if it also would be
> allowed in file scope for const qualified objects.

Nah, it doesn't really serve a useful purpose.  The only feature here is 
that the compiler will issue a diagnostic if the address is taken.

"Register" is a hint to the compiler, which the compiler can freely 
ignore.  In most cases (the only exception I know of is when using gcc 
with no optimisation enabled, running on a register-poor target), the 
compiler /will/ ignore it.  The compiler is /always/ free to keep data 
in a register, optimise it away fully, or whatever - the "register" 
keyword does not affect this in any way.

The actual uses of "register" that I can think of are:

Using gcc (and maybe other compilers) without optimisation, but where 
you still want a particular variable to go in a register.  Few people 
would miss that feature if it were removed.

Some compilers accept "volatile register" as meaning "do all the 
accesses as volatile commands, but keep the data in a register" (other 
compilers ignore the "register" part and force the data onto the stack). 
  I've used such constructs in the past during debugging, as a 
convenient place to put breakpoints.  Again, no one would miss it.

It can also be used on some compilers in connection with an "asm" 
statement to force a variable into a specific register.  This does have 
its uses in some sorts of embedded systems, though it is rare and very 
specialised.

>
>> But it will be a long time before compiler technology can figure out all
>> cases of "restrict" by itself - that requires insight between different
>> compile units, and hefty analysis on the way the functions are used.
>
> This will never come, because the compiler simply can't
> know. "restrict" is an interface specification that assures the called
> function that this particular pointer doesn't alias. This is an
> invariant that has to be checked at the calling side and relied upon
> on the called side. There is no general way to infer this at compile
> time if calling function and called function are compiled separately.
>

Correct.  Even with LTO and similar link-time optimisation getting more 
common, it is far from being standard.  And there will always be 
situations when LTO is not possible - thus cross-unit inferences cannot 
be made.

>> Similarly with "inline" - the compiler can figure out many functions
>> that should be inlined, but certainly not all.  There are plenty of
>> situations when the programmer knows that inlining a function will be
>> very efficient (perhaps due to constant folding), but the compiler
>> thinks the function is too large.  Compilers are getting better at this
>> (at least, gcc is), but they are not yet omnipotent.  And there are
>> situations where the programmer might want to disable automatic inlining
>> (to make debugging easier), but still want some functions inlined -
>> using the keyword explicitly gives that control.
>
> In C, "inline" is the only possibility to expose the definition of a
> function in a header file and not having it implemented repeatedly in
> every compilation unit (a static function would do that.)
>

Use "static inline" functions rather than plain "inline".

> Here again, if the compiler will really inline your function or not is
> subject to a lot of parameters, but you shouldn't care much about
> that: you did your best and exposed the definition to every
> compilation unit. And again, the name "inline" by itself is perhaps a
> misnomer, "dontProduceMultipleSymbolErrors" would have been
> a bit more verbose :)
>
> Jens
>

0
david2384 (2168)
8/29/2012 11:30:03 AM
On 08/29/2012 04:44 AM, David Brown wrote:
....
> I guess with C++, the "correct" way to handle type-punning is with 
> static_cast.  I don't know whether this guarantees the same alias-safe 
> characteristics as a type-punning union in C.

The relevant named cast is reinterpret_cast<>, not static_cast<>. While
it is safer than the corresponding C cast for a number of reasons,
avoiding aliasing issues is not one of those reasons. reinterpret_cast
is the least safe of the named casts, and should always be regarded as a
danger sign.
-- 
James Kuyper
0
jameskuyper (5635)
8/29/2012 12:07:33 PM
On 29/08/2012 14:07, James Kuyper wrote:
> On 08/29/2012 04:44 AM, David Brown wrote:
> ...
>> I guess with C++, the "correct" way to handle type-punning is with
>> static_cast.  I don't know whether this guarantees the same alias-safe
>> characteristics as a type-punning union in C.
>
> The relevant named cast is reinterpret_cast<>, not static_cast<>. While
> it is safer than the corresponding C cast for a number of reasons,
> avoiding aliasing issues is not one of those reasons. reinterpret_cast
> is the least safe of the named casts, and should always be regarded as a
> danger sign.
>

Accessing data through aliases with different types is always a 
"dangerous" operation.

The key point is whether or not this is guaranteed to work (assuming 
32-bit sizes for everything) :

unsigned int foo(float f) {
	float x;
	unsigned int y;

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

	return y;	// Return binary representation of float
}

In C, if the line used is "y = * ((unsigned int*) &x);", then the 
behaviour is undefined - the compiler "knows" that the float "x" cannot 
alias something that an "unsigned int *" pointer points at.

The safe way to do it in C is:

unsigned int fooC(float f) {
	union {
		float x;
		unsigned int y;
	} u;

	u.x = f;

	return u.y;	// Return binary representation of float
}

But I gather that is not guaranteed safe in C++.


0
david2384 (2168)
8/29/2012 12:49:47 PM
Am 29.08.2012 13:30, schrieb David Brown:
> On 29/08/2012 10:41, Jens Gustedt wrote:

>> In C, "inline" is the only possibility to expose the definition of a
>> function in a header file and not having it implemented repeatedly in
>> every compilation unit (a static function would do that.)
>>
> 
> Use "static inline" functions rather than plain "inline".

no, "static inline" as I already said is completely superfluous, it
buys you even less then "register". "static" does perfectly well,
then, if you only have a use like that.

"inline" allows to expose the definition in the header *and* to use it
as any other function, take addresses and compare them and stuff like
that, *and* avoids to have multiple copies scattered over your
different compilation units. Clean design. That is what "inline" was
invented for.

Jens

0
8/29/2012 1:25:05 PM
On 2012-08-28 16:30, James Kuyper wrote:
> On 08/28/2012 05:12 PM, Melzzzzz wrote:
>> On Tue, 28 Aug 2012 23:00:16 +0200
>> Jens Gustedt <jens.gustedt@loria.fr> wrote:
>>
>>>
>>> I'd still like to hear of a plausible use case for "void*" in C++ that
>>> is not related to C compability or to the overloading of "operator
>>> new".
>>>
>> Well, when implementing template container for pointers, it is great
>> optimization to use just single class specialized for pointers to void,
>> and cast to appropriate pointer type in specialized classes,
>> while using single implementation.
>> It greatly reduces code size.
>
> Given that C++ doesn't allow implicit conversions from void*, char* can
> be just about as good as void* for that kind of purpose.
>

The standard requires that casting from any object pointer type to void* 
and back preserves the original pointer value (5.2.9/13). That guarantee 
is not present for any other pointer type.
0
8/29/2012 3:09:18 PM
On 2012-08-29 01:02, Jens Gustedt wrote:
>>   Use void* not unsigned char* for untyped pointers in C++.
>
> What higher entity revealed you that commandment?
>
> Jens
>

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.
0
8/29/2012 3:12:56 PM
Am 29.08.2012 17:09, schrieb Casey Carter:
> On 2012-08-28 16:30, James Kuyper wrote:
>> On 08/28/2012 05:12 PM, Melzzzzz wrote:
>>> On Tue, 28 Aug 2012 23:00:16 +0200
>>> Jens Gustedt <jens.gustedt@loria.fr> wrote:
>>>
>>>>
>>>> I'd still like to hear of a plausible use case for "void*" in C++ that
>>>> is not related to C compability or to the overloading of "operator
>>>> new".
>>>>
>>> Well, when implementing template container for pointers, it is great
>>> optimization to use just single class specialized for pointers to void,
>>> and cast to appropriate pointer type in specialized classes,
>>> while using single implementation.
>>> It greatly reduces code size.
>>
>> Given that C++ doesn't allow implicit conversions from void*, char* can
>> be just about as good as void* for that kind of purpose.
>>
> 
> The standard requires that casting from any object pointer type to void*
> and back preserves the original pointer value (5.2.9/13).

right.

> That guarantee is not present for any other pointer type.

That is wrong. It also says (this is from C11 but I suppose that C++11
should have something similar):

   A pointer to void shall have the same representation and alignment
   requirements as a pointer to a character type.

It also says

   A pointer to an object type may be converted to a pointer to a
   different object type. If the resulting pointer is not correctly
   aligned for the referenced type, the behavior is
   undefined. Otherwise, when converted back again, the result shall
   compare equal to the original pointer.

So at least in C there is no problem in converting back and forth to
"unsigned char*". (Alignment is not a problem, since "char" types have
the weakest alignment requirements.) So the same guarantee as you
mention above for "void*" also holds for all character pointer types.


+++++

In any case, the use cases for "void*" in C++ haven't convinced me
much, yet. I still think that usage of "void*" is peripheral to C++
and mostly there to ensure interface compatibility with C.

Veritable C++ code that uses "void*" to implement say the common core
of a template library is not very clear with itself. For me such
things look more that the implementation of such a core would better
be done with the right tool. In the same way as it is sometimes
appropriate to use some inline assembler from C, it should be more
common praxis to use just pure C for the implementation of some type
agnostic core functionality.

Jens
0
8/29/2012 4:01:33 PM
On 08/29/2012 11:09 AM, Casey Carter wrote:
> On 2012-08-28 16:30, James Kuyper wrote:
....
>> Given that C++ doesn't allow implicit conversions from void*, char* can
>> be just about as good as void* for that kind of purpose.
>>
> 
> The standard requires that casting from any object pointer type to void* 
> and back preserves the original pointer value (5.2.9/13). That guarantee 
> is not present for any other pointer type.

Section 6.3.2.3p7 of the C standard says: "When a pointer to an object
is converted to a pointer to a character type, the result points to the
lowest addressed byte of the object. Successive increments of the
result, up to the size of the object, yield pointers to the remaining
bytes of the object." It says nothing about the reverse conversion, however.

In general, such a requirement would be inconsistent with the C++ object
model, but I'm surprised at being unable to find a corresponding
guarantee in the C++ standard for some restricted category of types,
such as "trivially copyable" or "standard layout" types.
0
jameskuyper (5635)
8/29/2012 4:03:20 PM
On 8/29/2012 1:02 AM, Jens Gustedt wrote:
> Am 29.08.2012 00:03, schrieb Leigh Johnston:
>> On 28/08/2012 22:58, Jens Gustedt wrote:
>>> Am 28.08.2012 23:25, schrieb Casey Carter:
>>>> Are you suggesting that C++ should forbid malloc, or that C++
>>>> should forbid void*, or that C++ should have some other type whose only
>>>> purpose is to represent void* returns from C functions?
>>>
>>> That it'd leave "void*" alone and uses it as it was originally defined
>>> in C. It just makes no sense. Somebody that uses C memory functions is
>>> beyond the red line anyhow. Requiring a cast here is just useless, and
>>> is not adding to compability, but the contrary.
>>>
>>> Use "unsigned char*" instead, when you feel the need of an untyped
>>> pointer inside C++, which should be rare in C++, anyhow.
>>
>> What utter nonsense mate.
>
> 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.


>>   Use void* not unsigned char* for untyped pointers in C++.
>
> 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.


0
cr88192355 (1928)
8/29/2012 5:08:28 PM
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*.
0
jameskuyper (5635)
8/29/2012 5:49:46 PM
On 29/08/2012 18:49, James Kuyper wrote:
> 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*.

char* is .. wait for it .. a pointer to char; void* is .. wait for it .. 
a pointer to anything; this has not changed from C to C++.  The lack of 
implicit conversion *from* void* does not change the utility of void*.

/Leigh

0
leigh (1128)
8/29/2012 6:16:24 PM
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?

0
jameskuyper (5635)
8/29/2012 6:34:56 PM
Am 29.08.2012 17:12, schrieb Casey Carter:
> On 2012-08-29 01:02, Jens Gustedt wrote:
>>>   Use void* not unsigned char* for untyped pointers in C++.
>>
>> What higher entity revealed you that comamandment?
>>
>> Jens
>>
> 
> 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

0
8/29/2012 6:36:36 PM
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.

/Leigh


0
leigh (1128)
8/29/2012 6:41:52 PM
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
0
8/29/2012 6:49:42 PM
On 08/29/2012 02:41 PM, Leigh Johnston wrote:
> 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*?

0
jameskuyper (5635)
8/29/2012 7:01:52 PM
On 2012-08-29 14:01, James Kuyper wrote:
> On 08/29/2012 02:41 PM, Leigh Johnston wrote:
>> 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.
0
8/29/2012 7:05:46 PM
On 29/08/2012 19:49, Jens Gustedt wrote:
> 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.

Indeed you can use a char* pointer to "inspect" the representation of 
other objects; an array of char can even be used to placement new an 
object of any type but this has little to do with void*; void* is used 
when you want a pointer to any type; a round-trip cast via void* is well 
defined.

>
>> 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 malloc is 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?

The utility is that void* can be used as a pointer to an object of any 
type; it is not obvious that a char* pointer is pointing to anything 
other than a char (even if it can).

>
> (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)

Use void* when you need an untyped pointer; such needs exist in both C 
and C++.

/Leigh
0
leigh (1128)
8/29/2012 7:09:04 PM
On 08/29/2012 03:05 PM, Casey Carter wrote:
> On 2012-08-29 14:01, James Kuyper wrote:
>> On 08/29/2012 02:41 PM, Leigh Johnston wrote:
>>> 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.

0
jameskuyper (5635)
8/29/2012 7:17:43 PM
On 08/29/2012 03:05 PM, Casey Carter wrote:
> On 2012-08-29 14:01, James Kuyper wrote:
>> On 08/29/2012 02:41 PM, Leigh Johnston wrote:
>>> 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.

0
jameskuyper (5635)
8/29/2012 7:18:06 PM
David Brown wrote 2012-08-29 09:51:

> But it will be a long time before compiler technology can figure out all
> cases of "restrict" by itself - that requires insight between different
> compile units, and hefty analysis on the way the functions are used.
>

The argument from the C++ camp, for not implementing it, is that it is a 
lot less useful in C++. Most functions don't take pointers to basic 
types as parameters, because C++ is largely class based.

Type based alias analysis will show that function parameters cannot 
alias, because they are of different class types. Adding restrict will 
not help.

If you have

void f(std::vector<int>& v1, std::vector<int>& v2)
{
    // Here v1[1] can never, ever alias v2[2]
    // because vectors don't work that way, and the compiler can tell
}

on the other hand, with C style code

void f(int* v1, int* v2)
{
    // Here any v1[i] might alias any v2[j]
    // because the function just COULD have been called
    // with f(p, p + 7)

}



Bo Persson

0
bop (1086)
8/29/2012 7:33:18 PM
Jens Gustedt skrev 2012-08-29 00:07:
> Am 28.08.2012 20:38, schrieb Bo Persson:
>> Jens Gustedt wrote 2012-08-27 18:34:
>>
>>> I am not sure that I understand this one. C has the optional uintXX_t
>>> that are guaranteed to have a fixed width no padding etc, if they
>>> exist. Would it for your purpose just suffice to make some of these
>>> types mandatory e.g for 8, 16, 32 and 64 bit integers?
>>>
>>
>> Why would you want to make this mandatory for everyone? Why not be
>> satisfied if your code is portable to systems having these types?
>
> 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

0
bop (1086)
8/29/2012 7:51:15 PM
Am 29.08.2012 21:09, schrieb Leigh Johnston:
> On 29/08/2012 19:49, Jens Gustedt wrote:
>> Am 29.08.2012 20:16, schrieb Leigh Johnston:
>>> 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 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 :)

>> 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)
> 
> 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
0
8/29/2012 8:33:08 PM
On 29/08/2012 21:33, Jens Gustedt wrote:
> Am 29.08.2012 21:09, schrieb Leigh Johnston:
>> On 29/08/2012 19:49, Jens Gustedt wrote:
>>> Am 29.08.2012 20:16, schrieb Leigh Johnston:
>>>> 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 malloc is useless?
>
> not in C, where implicit conversion from "void*" works without
> problems

Ergo void* is not useless in C.

>
> or where you refering to C++? using malloc? doesn't that give you
> objects for which the constructor isn't called :)

I never use malloc in a C++ program.

>
>>> 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)
>>
>> 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?

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).

Another example: an object pointer passed to /pthread_create/.

/Leigh
0
leigh (1128)
8/29/2012 8:43:33 PM
Am 29.08.2012 22:43, schrieb Leigh Johnston:
> On 29/08/2012 21:33, Jens Gustedt wrote:
>> Am 29.08.2012 21:09, schrieb Leigh Johnston:
>>> On 29/08/2012 19:49, Jens Gustedt wrote:
>>>> Am 29.08.2012 20:16, schrieb Leigh Johnston:
>>>>> 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 malloc is useless?
>>
>> not in C, where implicit conversion from "void*" works without
>> problems
> 
> 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.

>> or where you refering to C++? using malloc? doesn't that give you
>> objects for which the constructor isn't called :)
> 
> I never use malloc in a C++ program.

see

>> you don't answer my question, still no example for a real use case in
>> C++, could you be more concrete?
> 
> 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
0
8/29/2012 9:23:54 PM
On 2012-08-29 16:23, Jens Gustedt wrote:
> 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?

0
8/29/2012 10:21:32 PM
On 29/08/2012 22:23, Jens Gustedt wrote:
> Am 29.08.2012 22:43, schrieb Leigh Johnston:
>> On 29/08/2012 21:33, Jens Gustedt wrote:
>>> Am 29.08.2012 21:09, schrieb Leigh Johnston:
>>>> On 29/08/2012 19:49, Jens Gustedt wrote:
>>>>> Am 29.08.2012 20:16, schrieb Leigh Johnston:
>>>>>> 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 malloc is useless?
>>>
>>> not in C, where implicit conversion from "void*" works without
>>> problems
>>
>> 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++.

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.

>
> 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.

Correct; perhaps this is what you meant.

>
>>> or where you refering to C++? using malloc? doesn't that give you
>>> objects for which the constructor isn't called :)
>>
>> I never use malloc in a C++ program.
>
> see

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

>
>>> you don't answer my question, still no example for a real use case in
>>> C++, could you be more concrete?
>>
>> 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.

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

>
>> 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++.

Of course it is a proper use case for C++; /pthread_create/ is callable 
from C++.

/Leigh

0
leigh (1128)
8/29/2012 10:21:34 PM
Jens Gustedt <jens.gustedt@loria.fr> writes:
[...]
> 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).

[...]

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
8/29/2012 11:19:45 PM
On 30/08/2012 00:21, Leigh Johnston wrote:
> On 29/08/2012 22:23, Jens Gustedt wrote:
>> 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.
>
> 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.

0
luca.risolia (195)
8/30/2012 12:38:38 AM
James Kuyper <jameskuyper@verizon.net> writes:
> 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?

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.)

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
8/30/2012 12:53:26 AM
On 2012-08-29, David Brown <david@westcontrol.removethisbit.com> wrote:

> 	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.

0
raka (11)
8/30/2012 4:44:35 AM
On 2012-08-29 23:44, Adrian Ratnapala wrote:
> On 2012-08-29, David Brown <david@westcontrol.removethisbit.com> wrote:
>
>> 	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.
>

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;
0
8/30/2012 5:20:56 AM
Am 30.08.2012 00:21, schrieb Leigh Johnston:
> On 29/08/2012 22:23, Jens Gustedt wrote:
>> Am 29.08.2012 22:43, schrieb Leigh Johnston:
>>> On 29/08/2012 21:33, Jens Gustedt wrote:
>>>> Am 29.08.2012 21:09, schrieb Leigh Johnston:
>>>>> On 29/08/2012 19:49, Jens Gustedt wrote:
>>>>>> Am 29.08.2012 20:16, schrieb Leigh Johnston:
>>>>>>> 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 malloc is useless?
>>>>
>>>> not in C, where implicit conversion from "void*" works without
>>>> problems
>>>
>>> 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++.
> 
> 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.
> 
>>
>> 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.
> 
> Correct; perhaps this is what you meant.

Yes, this is what I said.

>>
>>>> or where you refering to C++? using malloc? doesn't that give you
>>>> objects for which the constructor isn't called :)
>>>
>>> I never use malloc in a C++ program.
>>
>> see
> 
> 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++.

>>
>>>> you don't answer my question, still no example for a real use case in
>>>> C++, could you be more concrete?
>>>
>>> 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.
> 
> 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?

>>> 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++.
> 
> 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
0
8/30/2012 6:46:10 AM
On 30/08/2012 06:44, Adrian Ratnapala wrote:
> On 2012-08-29, David Brown <david@westcontrol.removethisbit.com> wrote:
>
>> 	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.
>

I have never actually used reinterpret_cast in C++ - my C++ experience 
is fairly minimal in general - so I'm happy to be corrected!

However, in this case I specifically wanted to go through a pointer.  I 
realise that reinterpret_cast will not change the bit pattern (unlike 
with C "y = (unsigned int) f"), and that therefore the effect should be 
the same with or without the pointer syntax.

But what I am interested in is how the aliasing rules work when using 
pointers.  Without pointers, the compiler will clearly see that the 
variables are being used directly, and use the data correctly.  But with 
pointers, will it assume that a "unsigned int*" pointer cannot alias a 
float?  Real world uses of this sort of thing often involve moving lumps 
of data around using pointers - this is just a simple example in which 
the "lump" is a single item in size.

0
david2384 (2168)
8/30/2012 7:01:43 AM
Am 30.08.2012 00:21, schrieb Casey Carter:
> On 2012-08-29 16:23, Jens Gustedt wrote:
>> 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 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


0
8/30/2012 7:06:59 AM
Am 30.08.2012 02:38, schrieb Luca Risolia:
> On 30/08/2012 00:21, Leigh Johnston wrote:
>> On 29/08/2012 22:23, Jens Gustedt wrote:
>>> 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.
>>
>> 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.

So ok, can I conclude that "void*" had been useful in C++ in early
stages when the tools chains where not yet there where the designers
of C++ wanted it to be?

Sure that is a valid use case. Historically it would perhaps been
better to say:

  "ok, these things can't be done with C++, yet, let's use C until we
   can get rid of it"

So if I understand correctly, such a use should now be more and more
rare, if not completely avoided in new code?

Jens

0
8/30/2012 7:11:33 AM
On 29/08/2012 21:33, Bo Persson wrote:
> David Brown wrote 2012-08-29 09:51:
>
>> But it will be a long time before compiler technology can figure out all
>> cases of "restrict" by itself - that requires insight between different
>> compile units, and hefty analysis on the way the functions are used.
>>
>
> The argument from the C++ camp, for not implementing it, is that it is a
> lot less useful in C++. Most functions don't take pointers to basic
> types as parameters, because C++ is largely class based.
>
> Type based alias analysis will show that function parameters cannot
> alias, because they are of different class types. Adding restrict will
> not help.
>
> If you have
>
> void f(std::vector<int>& v1, std::vector<int>& v2)
> {
>     // Here v1[1] can never, ever alias v2[2]
>     // because vectors don't work that way, and the compiler can tell
> }
>
> on the other hand, with C style code
>
> void f(int* v1, int* v2)
> {
>     // Here any v1[i] might alias any v2[j]
>     // because the function just COULD have been called
>     // with f(p, p + 7)
>
> }
>

I can see that for "pure" C++ code, "restrict" is much less important.

However, and this is the main thrust of this thread which the C++ 
committee don't seem to understand, people want to be able to re-use C 
code and C-style code within C++.

If I have a useful, tested, working C function of style "void f(int* v1, 
int*v2)", then I want to be able to use it in a C++ program.  In theory, 
C++ is supposed to let you do anything that you can do in C, and do it 
equally efficiently - you only "pay" for features that you use.  But 
lack of "restrict" means you /are/ paying for using C++ instead of C, 
and lack of other C features such as designated initialisers means you 
/can't/ do everything you could do in C.  (I expect the C++ committee 
thinks that with C++ classes, designated initialisers are not needed 
when you have constructors.)


While most code /written/ is for "big" computers (desktops, servers, and 
even mobile phones these days), most code that /runs/ is for smaller, 
embedded systems.  This code is traditionally written in C.  Much of it 
could be better written in a subset of C++.  To work well on embedded 
systems, you need to be efficient (cut out wastes of space such as RTTI) 
and predictable (drop all "exceptions"), you need to have tight control 
over memory (often you will run without any sort of heap - no "new" or 
even "malloc"), and you need simple and clear generated code (C-style 
arrays are typically far better than STL containers).

But there are plenty of C++ features that let the programmer create much 
better programs than C alone.  C++ can provide stronger type safety, 
better scoping, function overloading and default parameters, namespaces, 
encapsulation of data and methods - all for "free", with zero cost in 
code space or run-time.  Other features such as virtual methods will 
have a "cost", but it may be cheaper at run-time or at design-time than 
equivalent C solutions.  And templates are a mixed bag - sometimes they 
can give you much more efficient code, sometimes they can cause huge bloat.

However, as the C committee adds more and more power to the C language, 
the C++ committee says "you don't need that - you should be using 
classes!" or "you don't need those features in the language - here's a 
huge class template library that does almost the same thing".  The C++ 
committee is artificially widening the schism between the languages. 
And for what reason?  Are they afraid that adding "restrict", or 
fixed-point arithmetic types, would somehow hinder the C++ language?  Is 
it just language snobbery?  Are they worried about implementation? 
Barring one obvious example, /all/ C++ toolchains are both C and C++ 
toolchains.  Their compilers already support all (or almost all) C99 
features and will support C11 features too.  For gcc at least (I suspect 
the same applies to other compilers) you can often use additional C 
features in C++.


(A good rant in the morning is almost as good as a cup of coffee...)

0
david2384 (2168)
8/30/2012 7:38:20 AM
On 29/08/2012 20: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?
>

You skipped the important part of Leigh's post - "char* is .. wait for 
it .. a pointer to char; void* is .. wait for it .. a pointer to 
anything; this has not changed from C to C++."

If you write in your code "char* p", you are saying that "p is a pointer 
to a character or a list of characters".  If you write "void* p", you 
are saying that "p points to something which could be anything".

These are different things.  It really doesn't matter how these are 
implemented, and what casts can be done implicitly or explicitly - they 
/say/ different things.  Your compiler will spend milliseconds reading 
your code, and doesn't care about style, logic, or readability.  But 
programmers might spend days reading it or writing it, and they might 
need to do so again after years have passed.  This is why you write code 
that says what it should say.  This is why you never use an "unsigned 
char" to store a small number, but rather use an "uint8_t" - it does 
exactly the same thing, but makes the purpose clear.

0
david2384 (2168)
8/30/2012 7:47:25 AM
Am 30.08.2012 09:47, schrieb David Brown:
> On 29/08/2012 20: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?
>>
> 
> You skipped the important part of Leigh's post - "char* is .. wait for
> it .. a pointer to char; void* is .. wait for it .. a pointer to
> anything; this has not changed from C to C++."
> 
> If you write in your code "char* p", you are saying that "p is a pointer
> to a character or a list of characters".  If you write "void* p", you
> are saying that "p points to something which could be anything".
> 
> These are different things.  It really doesn't matter how these are
> implemented, and what casts can be done implicitly or explicitly - they
> /say/ different things.  Your compiler will spend milliseconds reading
> your code, and doesn't care about style, logic, or readability.  But
> programmers might spend days reading it or writing it, and they might
> need to do so again after years have passed.  This is why you write code
> that says what it should say.  This is why you never use an "unsigned
> char" to store a small number, but rather use an "uint8_t" - it does
> exactly the same thing, but makes the purpose clear.

You probably didn't see my reply to that either, this thread got
somehow out of bounds.

You just should push the button a bit further where Leigh stopped. He
resolved the term "void" but didn't for "char". "char" is the smallest
addressable unit in C and C++ (Pascal had byte for that, no) that is
almost completely stripped of a semantic interpretation.

Traditionally "char*" was also that, a pointer to a region of
unspecific bytes. Nowadays "unsigned char*" serves that purpose,
because it has the advantage of letting you access any bit (!) and
bite of the data and you'd don't have confusion with the other
completely orthogonal use of "char*" for C strings.

Semantically I don't see much difference with that respect between
"void*" and "unsigned char*". Both are pointers to unspecific
data. They have different properties, sure, one of my interest in this
thread was to know about what properties people actually use. (And
from the C++ side I only got partial answers, yet.)

And you are completely right with your argument that small numbers
that are meant as such should use "uint8_t" or similar and not
"unsigned char". Generally, in C you should use the semantic
predefined typedef's as much as possible to mark your intent with a
particular data.

Jens
0
8/30/2012 8:17:37 AM
On 08/30/2012 03:47 AM, David Brown wrote:
> On 29/08/2012 20:34, James Kuyper 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?
>>
> 
> You skipped the important part of Leigh's post - "char* is .. wait for 
> it .. a pointer to char; void* is .. wait for it .. a pointer to 
> anything; this has not changed from C to C++."
> 
> If you write in your code "char* p", you are saying that "p is a pointer 
> to a character or a list of characters".  If you write "void* p", you 
> are saying that "p points to something which could be anything".

Yes, I skipped that, because I considered it an unimportant and silly
distinction. It's the functional differences between char* and void*
that render void* the appropriate way to store a pointer of unknown
type; remove those functional differences, and I wouldn't bother using
'void*' rather than 'char*' just because 'void*' documents a supposedly
different meaning. My point being that C++ lacks some (though not yet
all) of the functional differences that C has between those two types.

> These are different things.  It really doesn't matter how these are 
> implemented, and what casts can be done implicitly or explicitly - they 
> /say/ different things.

If they were functionally equivalent, the fact that they had different
names wouldn't mean that they actually say anything different, however
much you might want to think otherwise.
-- 
James Kuyper
0
jameskuyper (5635)
8/30/2012 12:05:16 PM
On 30/08/2012 14:05, James Kuyper wrote:
> On 08/30/2012 03:47 AM, David Brown wrote:
>> On 29/08/2012 20:34, James Kuyper 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?
>>>
>>
>> You skipped the important part of Leigh's post - "char* is .. wait for
>> it .. a pointer to char; void* is .. wait for it .. a pointer to
>> anything; this has not changed from C to C++."
>>
>> If you write in your code "char* p", you are saying that "p is a pointer
>> to a character or a list of characters".  If you write "void* p", you
>> are saying that "p points to something which could be anything".
>
> Yes, I skipped that, because I considered it an unimportant and silly
> distinction. It's the functional differences between char* and void*
> that render void* the appropriate way to store a pointer of unknown
> type; remove those functional differences, and I wouldn't bother using
> 'void*' rather than 'char*' just because 'void*' documents a supposedly
> different meaning. My point being that C++ lacks some (though not yet
> all) of the functional differences that C has between those two types.
>
>> These are different things.  It really doesn't matter how these are
>> implemented, and what casts can be done implicitly or explicitly - they
>> /say/ different things.
>
> If they were functionally equivalent, the fact that they had different
> names wouldn't mean that they actually say anything different, however
> much you might want to think otherwise.
>

That is obviously incorrect.  A comment is functionally equivalent to 
white space - are you suggesting that comments do not "say" anything in 
source code?

A "char *" says "this is a pointer to a character", while a "void *" 
says "this is a pointer to an unknown type".  These convey different 
meanings to the reader.

Clearly there is a certain amount of style - and therefore differing 
personal opinions - in these matters.  But you cannot deny the fact that 
different names for the same thing convey different meanings beyond 
their function.

0
david2384 (2168)
8/30/2012 12:54:07 PM
On 2012-08-30 01:46, Jens Gustedt wrote:
> So again give me a proper use case in C++ that isn't just for calling
> a C interface.

void* is used to point at space that has been allocated but not yet 
initialized or destroyed but not yet freed to indicate that references 
to that space are semantically invalid.
0
8/30/2012 1:39:08 PM
Jens Gustedt <jens.gustedt@loria.fr> writes:
>Am 30.08.2012 00:21, schrieb Casey Carter:
>> On 2012-08-29 16:23, Jens Gustedt wrote:
>>> 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 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
>

What about the existing massive volumes of C++ code which use void*?  Particularly
code that dates from the 80's when there was no STL?
0
scott1 (423)
8/30/2012 1:53:21 PM
On Wednesday, August 29, 2012 10:51:59 AM UTC+3, David Brown wrote:
> On 28/08/2012 19:14, =D6=F6 Tiib wrote:
> > static_assert about sizeof guarantees that it won't compile. For bit or=
der
> > and padding you need bit more complex static asserts.
>=20
> Yes, I use static_assert to check all these things.  Once I get to use=20
> newer C (or C++) standards with real static_assert, I'll be happy.  At=20
> the moment, I use macros that end up causing errors (arrays with=20
> negative sizes) on assertion failures - they are messy, and give weird=20
> error messages if they are triggered, but they are a great help anyway.

So it just takes time, but standards have already given us a tool that
mitigates most problems with bit order, byte count and padding.

> > As about keywords like 'restrict', 'inline' or 'register' i am sure
>  > that on general case compiler and/or linker can optimize lot better
> > thanaverage Joe and so the keywords just add pointless bloat.
>=20
> But it will be a long time before compiler technology can figure out all=
=20
> cases of "restrict" by itself - that requires insight between different=
=20
> compile units, and hefty analysis on the way the functions are used.

I feel that every time the standards drop some optimization on our
shoulders they have later to take it away. Joes create a mess with
it that does not compile or makes some compiler to lose in competition. 'in=
line' is only hint now (at least in C++) and both its presence
and lack does guarantee nothing.

> Similarly with "inline" - the compiler can figure out many functions=20
> that should be inlined, but certainly not all.  There are plenty of=20
> situations when the programmer knows that inlining a function will be=20
> very efficient (perhaps due to constant folding), but the compiler=20
> thinks the function is too large.  Compilers are getting better at this=
=20
> (at least, gcc is), but they are not yet omnipotent.  And there are=20
> situations where the programmer might want to disable automatic inlining=
=20
> (to make debugging easier), but still want some functions inlined -=20
> using the keyword explicitly gives that control.

Things that guarantee something i love. Does 'restrict' guarantee
some different behavior? Then i take my words back ... then it should
be keyword in C++ as well. I had impression that it was another "maybe
optimize" feature like 'register' and 'inline'. Then compiler could
generate versions with restrict and without if it matters and linker
could just choose and maybe inline instead.

> Perhaps I don't count as an "average Joe"...

For senior developer there should be standardized something that guarantee
certain optimizations or turn them off like gcc attributes noinline and
always_inline. The syntax must be really ugly so average Joe can see that
it is senior developer's feature from far. Exactly like gcc has.=20

You are still probably more efficient (i am) when ganging up with others
and you have to be tolerant with them, everybody start as sub-average Joes.
 =20
Why do not they make 'inline' not mandatory for function definition in
include file as well? Make a logic that if file is #included then=20
function definition in it is implicitly 'inline' and let the compiler
and linker to decide what really happens (they anyway do). That would
remove all usage of 'inline' and Joes (and me) would be more happy.
0
ootiib (965)
8/30/2012 2:13:47 PM
On Wednesday, August 29, 2012 11:41:08 AM UTC+3, Jens Gustedt wrote:
> Am 29.08.2012 09:51, schrieb David Brown:
> > On 28/08/2012 19:14, =D6=F6 Tiib wrote:
> >> As about keywords like 'restrict', 'inline' or 'register' i am sure
> >> that on general case compiler and/or linker can optimize lot better
> >> thanaverage Joe and so the keywords just add pointless bloat.
>=20
> I disagree with all of these points.

Nice. Then there is something to discuss i hope.

> > For "register", then I agree entirely - it's only real use now is very
> > specialised cases when you want to fix data into a specific register fo=
r
> > use in assembly.
>=20
> No, register is a contract that the programmer signs. He promises to
> never take the address of that particular object. Whether or not the
> compiler uses this is another point, but he may put it in a veritable
> 'register' or into an immediate optimize it completely out or whatever
> pleases. And he *must* issue a diagnostic whenever an attempt is made
> to take the address of that object.

This is too subtle effect. If I want to forbid taking and storing=20
references or pointers to temporaries or locals then lot better is to
teach to people that it is bad idea, not use 'register' keyword
that has never been meant for that. Besides ... if clueless people
do it and get a compiler warning then they ignore that warning anyway.

> As such "register" is nowadays a misnomer, since it doesn't have much
> to do with hardware registers of the platform. It still serves a
> purpose, and actually it could serve much more if it also would be
> allowed in file scope for const qualified objects.

Like you put it i would qualify it as hack that confuses more than
helps. Just imagine a  coding standard that requires that all
locals to what address is not taken ever are declared as "registers".
To shorten it ... it will call such incorrect usage of 'register' as=20
"register-correctness".  :-D

> > But it will be a long time before compiler technology can figure out al=
l
> > cases of "restrict" by itself - that requires insight between different
> > compile units, and hefty analysis on the way the functions are used.
>=20
> This will never come, because the compiler simply can't
> know. "restrict" is an interface specification that assures the called
> function that this particular pointer doesn't alias. This is an
> invariant that has to be checked at the calling side and relied upon
> on the called side. There is no general way to infer this at compile
> time if calling function and called function are compiled separately.

Yes, compiler can't know. Ever heard of 'optimizing linker'? Yes such
linker has to generate code too ... but so what? =20

> > Similarly with "inline" - the compiler can figure out many functions
> > that should be inlined, but certainly not all.  There are plenty of
> > situations when the programmer knows that inlining a function will be
> > very efficient (perhaps due to constant folding), but the compiler
> > thinks the function is too large.  Compilers are getting better at this
> > (at least, gcc is), but they are not yet omnipotent.  And there are
> > situations where the programmer might want to disable automatic inlinin=
g
> > (to make debugging easier), but still want some functions inlined -
> > using the keyword explicitly gives that control.
>=20
> In C, "inline" is the only possibility to expose the definition of a
> function in a header file and not having it implemented repeatedly in
> every compilation unit (a static function would do that.)

So detect that file is #included and assume that it is 'inline'. Done.
All need for implicit 'inline' is removed from both languages.

> Here again, if the compiler will really inline your function or not is
> subject to a lot of parameters, but you shouldn't care much about
> that: you did your best and exposed the definition to every
> compilation unit. And again, the name "inline" by itself is perhaps a
> misnomer, "dontProduceMultipleSymbolErrors" would have been
> a bit more verbose :)

Yes. Can you bring any example where you would want the diagnostic
because you put definition into header but forgot 'inline'? I can't.=20
So i would like implicit 'dontProduceMultipleSymbolErrors' for all
#included function definitions.
0
ootiib (965)
8/30/2012 3:04:48 PM
Am 30.08.2012 14:54, schrieb David Brown:
> A "char *" says "this is a pointer to a character", while a "void *"
> says "this is a pointer to an unknown type".  These convey different
> meanings to the reader.

No a "char*" doesn't say pointer to character, that is you who is
putting the sematics here. It says "pointer to char" and nothing
else. (and "unsigned char*" does even less so define a pointer to an
"unsigned character", whatever that would be.)

> Clearly there is a certain amount of style - and therefore differing
> personal opinions - in these matters.  But you cannot deny the fact that
> different names for the same thing convey different meanings beyond
> their function.

Would you be more comfortable if the standard introduced a type alias
"byte" for "unsigned char"?

That would completely be conceivable. For example C11 introduces

typedef int errno_t;

but by reclaiming a different semantic for "errno_t" than for "int".

Jens
0
8/30/2012 4:13:56 PM
Am 30.08.2012 15:53, schrieb Scott Lurndal:
> Jens Gustedt <jens.gustedt@loria.fr> writes:
>> Am 30.08.2012 00:21, schrieb Casey Carter:
>>> On 2012-08-29 16:23, Jens Gustedt wrote:
>>>> 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 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
>>
> 
> What about the existing massive volumes of C++ code which use void*?  Particularly
> code that dates from the 80's when there was no STL?

I don't completely get the sense of your question. You mean to take
them as an example for uses cases? Or you want to emphasize that there
would be a problem with old code?

If (supposing that for a minute) C++ would align itself on the C usage
of "void*" no old code would break, since this all does a cast to the
target type, if I understand correctly.

Then, also I would tend to say that C++ code from the 80's wouldn't
compile with a modern compiler, anyhow. At least that is my narrow
experience with C++. The big project I have written some years ago,
still needs syntax adjustments at any major revision of g++.

Possibly there would be some other possible solutions to get C and C++
closer on that point. But before thinking of solutions I first wanted
to know if this corresponds to something real on the C++ side.

I conclude for myself that the reality is that (besides interfacing
with C) "void*" is less and less useful in C++. And that declaring
variables of type "void*" and manipulating them (and the objects they
represent) should be more considered the "C side" of the game.

Jens
0
8/30/2012 4:51:06 PM
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 08/30/2012 11:04 AM, �� Tiib wrote:
> On Wednesday, August 29, 2012 11:41:08 AM UTC+3, Jens Gustedt
> wrote:
>> Am 29.08.2012 09:51, schrieb David Brown:
>>> On 28/08/2012 19:14, �� Tiib wrote:
>>>> As about keywords like 'restrict', 'inline' or 'register' i
>>>> am sure that on general case compiler and/or linker can
>>>> optimize lot better thanaverage Joe and so the keywords just
>>>> add pointless bloat.
>> 
>> I disagree with all of these points.
> 
> Nice. Then there is something to discuss i hope.
[snip]
>>> But it will be a long time before compiler technology can
>>> figure out all cases of "restrict" by itself - that requires
>>> insight between different compile units, and hefty analysis on
>>> the way the functions are used.
>> 
>> This will never come, because the compiler simply can't know.
>> "restrict" is an interface specification that assures the called 
>> function that this particular pointer doesn't alias. This is an 
>> invariant that has to be checked at the calling side and relied
>> upon on the called side. There is no general way to infer this at
>> compile time if calling function and called function are compiled
>> separately.
> 
> Yes, compiler can't know. Ever heard of 'optimizing linker'? Yes
> such linker has to generate code too ... but so what?
> 
Ever heard of dynamic linking?
These are the options as I see them.
1) The compiler assumes that the function can alias.
2) The compiler assumes that the function cannot alias, optimizes
based on this, and calls that do alias are undefined bahavior and
likely fail.
3) The compiler respects the 'restrict' keyword.
4) The linker recompiles every library when it is dynamically loaded.

While an optimizing linker could replace use of 'restrict' for
statically linked function calls, it is unable to replacate it's
effects when dynamic linking is used.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.19 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJQP6PwAAoJEP8JewLaHvzSwHgIAIAP4GtXVOlQmCqrLWmcboeP
viosKhQ4yAhfo9zJEt12zp2fdbD8NTJKEzdKaaHVxSMp38WYb0cgvMDp2HTq2rsc
ZlKX7/fCMkNHyOs5p8FQYNghVWmsqtGls3B5g99k3ayBk1wm7N0ZrEKJ9oHkP84j
fzl8xyRdByH6KMhNvT/9x8Yyj69SdVgQzQpc/wbE3CrvBfvoq2K7scXH/iNNeiVU
sG6pvaElSciyVp2JbCIQ9wdT8RgyyOHZ0JZSFDU8eC3AGuIdw/l+H4Pv8SWpX7Vz
zRDwvvaYRrKo31xBQyJeu3oKRv91SvVd4HTOc7JVHMnrle7MRlUxyimFePOjrrE=
=PnBR
-----END PGP SIGNATURE-----
0
ghartshaw (25)
8/30/2012 5:33:36 PM
On 30/08/2012 17:13, Jens Gustedt wrote:
> Am 30.08.2012 14:54, schrieb David Brown:
>> A "char *" says "this is a pointer to a character", while a "void *"
>> says "this is a pointer to an unknown type".  These convey different
>> meanings to the reader.
>
> No a "char*" doesn't say pointer to character, that is you who is
> putting the sematics here. It says "pointer to char" and nothing
> else. (and "unsigned char*" does even less so define a pointer to an
> "unsigned character", whatever that would be.)
>
>> Clearly there is a certain amount of style - and therefore differing
>> personal opinions - in these matters.  But you cannot deny the fact that
>> different names for the same thing convey different meanings beyond
>> their function.
>
> Would you be more comfortable if the standard introduced a type alias
> "byte" for "unsigned char"?

You are forgetting that in C++ we also have class types so we want 
pointers to "objects" not just pointers to "bytes".  Using void* to 
indicate that it is a pointer to anything (including any class type) is 
perfectly reasonable C++ IMO.  void* is alive and well in C++ Land even 
if it is used less than in C Land.

/Leigh
0
leigh (1128)
8/30/2012 5:39:28 PM
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 08/30/2012 12:13 PM, Jens Gustedt wrote:
> Am 30.08.2012 14:54, schrieb David Brown:
>> A "char *" says "this is a pointer to a character", while a "void
>> *" says "this is a pointer to an unknown type".  These convey
>> different meanings to the reader.
> 
> No a "char*" doesn't say pointer to character, that is you who is 
> putting the sematics here. It says "pointer to char" and nothing 
> else. (and "unsigned char*" does even less so define a pointer to
> an "unsigned character", whatever that would be.)
> 

'char *' says "this is a pointer to an object of type 'char'",
'unsigned char *' says "this is a pointer to an object of type
'unsigned char'", 'void *' says "this is a pointer to an object of an
unknown/any type".

If you want to interpret an object as a sequence of bytes, then use
'unsigned char *' or 'uint8_t *'. I see 'unsigned char' as meaning a
character in an encoding that is represented as an 8-bit unsigned
integer, while 'uint8_t' is an arbitrary 8-bit unsigned integer. (e.g.
I would write "unsigned char a = 'a'" and "uint8_t b = 10", but not
"unsigned char c = 10" or "uint8_t d = 'd'")

If on the other hand you wish to have an opaque pointer to an object
of unknown type, or to an uninitialized memory region, then use 'void *'.

Even if 'void *' was redefined to mean 'unsigned char *', I would
still distinguish between their uses just as I distinguish between
'unsigned char' and 'uint8_t'.

>> Clearly there is a certain amount of style - and therefore
>> differing personal opinions - in these matters.  But you cannot
>> deny the fact that different names for the same thing convey
>> different meanings beyond their function.
> 
> Would you be more comfortable if the standard introduced a type
> alias "byte" for "unsigned char"?
> 
> That would completely be conceivable. For example C11 introduces
> 
> typedef int errno_t;
> 
> but by reclaiming a different semantic for "errno_t" than for
> "int".
> 
> Jens
> 
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.19 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJQP6eRAAoJEP8JewLaHvzSOKkIAKpJG+LK1H1IcKMNdIrbzrgt
+GZskz9DpN5YUUCdAWWI1XbNwm0qJnmmzWvXEBm8ajDnyzwoBnBo89ss0KrbXC9+
J5TfAP21aXFCdPcbGpCVD8LvwKvrj6mu0s5vTkqh+BNfPBfOVKGkvvCL5EpsE8tw
f0mEoZf6vkaHez9A5GFW4j2RJh5wkJXy9s8fnPiY7pUqXGoIGF0JyUDo9Y1IQq5b
//yCE9qiLEnDbjthwyexkdqOIHv9VTj0TqkATeKp2wZIL3h6d6KGBozNrJmbmeJN
pxSYSBz9+pTOxP7ELLp2uWQcC9ED7JeCOdYwu0x/0Cyg2T0qdpPS9EQQYn4x4kQ=
=8ONX
-----END PGP SIGNATURE-----
0
ghartshaw (25)
8/30/2012 5:49:06 PM
On 08/30/2012 08:54 AM, David Brown wrote:
> On 30/08/2012 14:05, James Kuyper wrote:
>> On 08/30/2012 03:47 AM, David Brown wrote:
>>> On 29/08/2012 20:34, James Kuyper 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?
>>>>
>>>
>>> You skipped the important part of Leigh's post - "char* is .. wait for
>>> it .. a pointer to char; void* is .. wait for it .. a pointer to
>>> anything; this has not changed from C to C++."
>>>
>>> If you write in your code "char* p", you are saying that "p is a pointer
>>> to a character or a list of characters".  If you write "void* p", you
>>> are saying that "p points to something which could be anything".
>>
>> Yes, I skipped that, because I considered it an unimportant and silly
>> distinction. It's the functional differences between char* and void*
>> that render void* the appropriate way to store a pointer of unknown
>> type; remove those functional differences, and I wouldn't bother using
>> 'void*' rather than 'char*' just because 'void*' documents a supposedly
>> different meaning. My point being that C++ lacks some (though not yet
>> all) of the functional differences that C has between those two types.
>>
>>> These are different things.  It really doesn't matter how these are
>>> implemented, and what casts can be done implicitly or explicitly - they
>>> /say/ different things.
>>
>> If they were functionally equivalent, the fact that they had different
>> names wouldn't mean that they actually say anything different, however
>> much you might want to think otherwise.
>>
> 
> That is obviously incorrect.  A comment is functionally equivalent to 
> white space - are you suggesting that comments do not "say" anything in 
> source code?

Comments are for talking with other humans; the active part of the
language is for talking to the compiler. If the differences, for the
compiler, between 'void*' and 'char*' were reduced to a matter of how
they were spelled, I would not recommend using that spelling to convey
meaningful information to any humans who were reading the code.

This assertion is somewhat inconsistent with the fact that I have chosen
to use distinctions between other equivalent constructs to convey actual
meanings. For instance, when writing function declarations in C, I use T
*parameter_name to represent a pointer to a single object, and T
parameter_name[] when it is a pointer to the first in a series of
objects (in C++ I would use a reference for the first purpose).

I'll not bother to try and excuse the inconsistency; I'll just say that
the pointer parameter thing feels harmless to me, whereas I feel a
strong antipathy about removing the distinctions between void* and char*
(I really dislike the gnu extension that allows pointer arithmetic on
void*).

0
jameskuyper (5635)
8/30/2012 5:57:43 PM
=D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=97=D7=9E=D7=99=
=D7=A9=D7=99, 30 =D7=91=D7=90=D7=95=D7=92=D7=95=D7=A1=D7=98 2012 18:57:44 U=
TC+1, =D7=9E=D7=90=D7=AA James Kuyper:
> On 08/30/2012 08:54 AM, David Brown wrote:
>=20
> I'll not bother to try and excuse the inconsistency; I'll just say that=
=20
> the pointer parameter thing feels harmless to me, whereas I feel a
> strong antipathy about removing the distinctions between void* and char*
> (I really dislike the gnu extension that allows pointer arithmetic on
> void*).
>
The problem is that often void * are to objects, which you need to copy. Fo=
r instance if you're writing a qsort() style sorting routine, or a general-=
purose compressor, you'll need to cast to unsigned char * to actually acces=
s the bits.
0
8/30/2012 7:25:54 PM
Garrett Hartshaw <ghartshaw@gmail.com> writes:
[...]
> If you want to interpret an object as a sequence of bytes, then use
> 'unsigned char *' or 'uint8_t *'. I see 'unsigned char' as meaning a
> character in an encoding that is represented as an 8-bit unsigned
> integer, while 'uint8_t' is an arbitrary 8-bit unsigned integer. (e.g.
> I would write "unsigned char a = 'a'" and "uint8_t b = 10", but not
> "unsigned char c = 10" or "uint8_t d = 'd'")
[...]

Strictly speaking, `unsigned char *` and `uint8_t *` are not
interchangeable.  `unsigned char` is one byte by definition.
`uint8_t` is 8 bits by definition -- and if CHAR_BIT > 8, then
`uint8_t` will not exist.

C's treatment of characters is a bit of a mess IMHO, partly due to
changes in character semantics since C was first defined.  When we
could assume 7-bit ASCII (or 8-bit EBCDIC with plain char being
unsigned), C's model worked.  With the introduction of ASCII-based
8-bit character representations, with plain char remaining signed
on many systems, things started getting confusing.

Conflating the concepts of a single character and a single
fundamental storage unit into the types `char`, `signed char`, and
`unsigned char`, all required to be the same size, no longer makes
as much sense now as it did then.

If I were designing a C-like language from scratch today, I'd
separate the concepts of characters and fundamental storage units.
I'd probably also separate the concept of very short integers
from both.  So `char`, `byte`, and `int8` might be three distinct
and incompatible types.

Making such a change to C now would break so much code that the
resulting language could not reasonably be called "C"; it ain't
gonna happen.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
8/30/2012 9:07:49 PM
Am 30.08.2012 19:49, schrieb Garrett Hartshaw:
> 'char *' says "this is a pointer to an object of type 'char'",
> 'unsigned char *' says "this is a pointer to an object of type
> 'unsigned char'", 'void *' says "this is a pointer to an object of an
> unknown/any type".

no, at least for C "void" is a type, too.

   The void type comprises an empty set of values; it is an incomplete
   object type that cannot be completed.

so "void*" says pointer to void. This is not "nothing" or "unknown",
in that sense void is not much different from "struct nix" when you
never actually define "struct nix" somewhere. It behaves a bit
different in terms of implicit conversions, sure, but the sematic is
the same.

> If you want to interpret an object as a sequence of bytes, then use
> 'unsigned char *' or 'uint8_t *'. I see 'unsigned char' as meaning a
> character in an encoding that is represented as an 8-bit unsigned
> integer, while 'uint8_t' is an arbitrary 8-bit unsigned integer. (e.g.
> I would write "unsigned char a = 'a'" and "uint8_t b = 10", but not
> "unsigned char c = 10" or "uint8_t d = 'd'")
> 
> If on the other hand you wish to have an opaque pointer to an object
> of unknown type, or to an uninitialized memory region, then use 'void *'.

A "void*" pointer is not "an uninitialized" memory region. It may well
already be initialized.

But I am really surprised about this strong need of opaque pointer in
C++. If we follow the basic ideas of C++ such a usage should be very
rare in C++, no? Isn't that what "abstract base classes" have been
invented for?

> Even if 'void *' was redefined to mean 'unsigned char *', I would
> still distinguish between their uses just as I distinguish between
> 'unsigned char' and 'uint8_t'.

Therefore I had my question that came afterward and that you seem to
have overlooked:

>> Would you be more comfortable if the standard introduced a type
>> alias "byte" for "unsigned char"?
> 
>> That would completely be conceivable. For example C11 introduces
> 
>> typedef int errno_t;
> 
>> but by reclaiming a different semantic for "errno_t" than for
>> "int".

The naming of "char" (and the two others) certainly doesn't cover all
its uses that these type nowadays have, and it would be good to find
semantic names for the different use cases.

typedef char byte_t;            // for the minimal addressable storage unit
typedef unsigned char bitX_t;   // for an arbitrary collection of
unspecific data, usually X == 8
typedef unsigned char uintX_t;  // for use as small unsigned integer,
usually X == 8
typedef signed char intX_t;     // for use as small signed integer,
usually X == 8

Jens
0
8/30/2012 10:18:33 PM
Am 30.08.2012 17:04, schrieb �� Tiib:
> On Wednesday, August 29, 2012 11:41:08 AM UTC+3, Jens Gustedt wrote:
> This is too subtle effect. If I want to forbid taking and storing 
> references or pointers to temporaries or locals then lot better is to
> teach to people that it is bad idea, not use 'register' keyword
> that has never been meant for that.

Hm, this is a strong statement. It is the only observable impact that
the register keyword has in C. BTW the concept of an "object that
could have been declared with the register keyword" appears in C and
makes an important difference for the status of uninitialized objects.

> Besides ... if clueless people
> do it and get a compiler warning then they ignore that warning anyway.
> 
>> As such "register" is nowadays a misnomer, since it doesn't have much
>> to do with hardware registers of the platform. It still serves a
>> purpose, and actually it could serve much more if it also would be
>> allowed in file scope for const qualified objects.
> 
> Like you put it i would qualify it as hack that confuses more than
> helps. Just imagine a  coding standard that requires that all
> locals to what address is not taken ever are declared as "registers".
> To shorten it ... it will call such incorrect usage of 'register' as 
> "register-correctness".  :-D

well, I am not much convinced of this

>>> But it will be a long time before compiler technology can figure out all
>>> cases of "restrict" by itself - that requires insight between different
>>> compile units, and hefty analysis on the way the functions are used.
>>
>> This will never come, because the compiler simply can't
>> know. "restrict" is an interface specification that assures the called
>> function that this particular pointer doesn't alias. This is an
>> invariant that has to be checked at the calling side and relied upon
>> on the called side. There is no general way to infer this at compile
>> time if calling function and called function are compiled separately.
> 
> Yes, compiler can't know. Ever heard of 'optimizing linker'? Yes such
> linker has to generate code too ... but so what?  

Hm, you are telling me that an optimizing linker could be able to
distinguish between "memcpy" and "memmove" and then would be able to
link against the correct function? In any situation where an imaginary
"copy" function is called it could distinguish at link time if the two
memory regions overlap or not? Good to hear.

>>> Similarly with "inline" - the compiler can figure out many functions
>>> that should be inlined, but certainly not all.  There are plenty of
>>> situations when the programmer knows that inlining a function will be
>>> very efficient (perhaps due to constant folding), but the compiler
>>> thinks the function is too large.  Compilers are getting better at this
>>> (at least, gcc is), but they are not yet omnipotent.  And there are
>>> situations where the programmer might want to disable automatic inlining
>>> (to make debugging easier), but still want some functions inlined -
>>> using the keyword explicitly gives that control.
>>
>> In C, "inline" is the only possibility to expose the definition of a
>> function in a header file and not having it implemented repeatedly in
>> every compilation unit (a static function would do that.)
> 
> So detect that file is #included and assume that it is 'inline'. Done.
> All need for implicit 'inline' is removed from both languages.
> 
>> Here again, if the compiler will really inline your function or not is
>> subject to a lot of parameters, but you shouldn't care much about
>> that: you did your best and exposed the definition to every
>> compilation unit. And again, the name "inline" by itself is perhaps a
>> misnomer, "dontProduceMultipleSymbolErrors" would have been
>> a bit more verbose :)
> 
> Yes. Can you bring any example where you would want the diagnostic
> because you put definition into header but forgot 'inline'? I can't. 
> So i would like implicit 'dontProduceMultipleSymbolErrors' for all
> #included function definitions.

You mean a function definition that comes from the inclusion of a .h
file, I suppose. At least for the moment in C (and probably C++, too)
there is no distinction into different types of source files.

An function definition that is generated by a macro, would be
accounted in which class?

Jens
0
8/30/2012 10:39:06 PM
Jens Gustedt <jens.gustedt@loria.fr> writes:
> Am 30.08.2012 19:49, schrieb Garrett Hartshaw:
>> 'char *' says "this is a pointer to an object of type 'char'",
>> 'unsigned char *' says "this is a pointer to an object of type
>> 'unsigned char'", 'void *' says "this is a pointer to an object of an
>> unknown/any type".
>
> no, at least for C "void" is a type, too.

Yes, void is a type; specifically, it's an incomplete type that cannnot
be completed.

>    The void type comprises an empty set of values; it is an incomplete
>    object type that cannot be completed.
>
> so "void*" says pointer to void. This is not "nothing" or "unknown",
> in that sense void is not much different from "struct nix" when you
> never actually define "struct nix" somewhere. It behaves a bit
> different in terms of implicit conversions, sure, but the sematic is
> the same.

Not really.  A `char*` pointer points to an object of type `char`.  A
`void*` pointer does not point to an object of type `void`, because
there is no such thing.

Any type of pointer to object or incomplete type (i.e., any pointer
other than a function pointer) points to some object in memory (or to
nothing if it's currently a null pointer).  What's special about `void*`
is that, while you can perform certain pointer operations on it, you
can't access the object it points to without first converting it to some
other pointer type.

[...]

>> If on the other hand you wish to have an opaque pointer to an object
>> of unknown type, or to an uninitialized memory region, then use 'void *'.
>
> A "void*" pointer is not "an uninitialized" memory region. It may well
> already be initialized.

I think that was a recommendation for *how* to use `void*`, not a
statement about what `void* means to the compiler.

[...]

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
8/31/2012 12:30:53 AM
On Thursday, August 30, 2012 8:36:57 PM UTC+3, Garrett Hartshaw wrote:
> On 08/30/2012 11:04 AM, =D6=F6 Tiib wrote:
> > On Wednesday, August 29, 2012 11:41:08 AM UTC+3, Jens Gustedt
> > wrote:
> >> Am 29.08.2012 09:51, schrieb David Brown:
> >>> On 28/08/2012 19:14, =D6=F6 Tiib wrote:
> >>>> As about keywords like 'restrict', 'inline' or 'register' i
> >>>> am sure that on general case compiler and/or linker can
> >>>> optimize lot better thanaverage Joe and so the keywords just
> >>>> add pointless bloat.
> >>=20
> >> I disagree with all of these points.
> >=20
> > Nice. Then there is something to discuss i hope.
> [snip]
> >>> But it will be a long time before compiler technology can
> >>> figure out all cases of "restrict" by itself - that requires
> >>> insight between different compile units, and hefty analysis on
> >>> the way the functions are used.
> >>=20
> >> This will never come, because the compiler simply can't know.
> >> "restrict" is an interface specification that assures the called=20
> >> function that this particular pointer doesn't alias. This is an=20
> >> invariant that has to be checked at the calling side and relied
> >> upon on the called side. There is no general way to infer this at
> >> compile time if calling function and called function are compiled
> >> separately.
> >=20
> > Yes, compiler can't know. Ever heard of 'optimizing linker'? Yes
> > such linker has to generate code too ... but so what?
> >=20
> Ever heard of dynamic linking?

Certainly. It is part of our everyday work, despite neither language define=
s
anything that matters in that respect.

> These are the options as I see them.
> 1) The compiler assumes that the function can alias.
> 2) The compiler assumes that the function cannot alias, optimizes
> based on this, and calls that do alias are undefined bahavior and
> likely fail.
> 3) The compiler respects the 'restrict' keyword.
> 4) The linker recompiles every library when it is dynamically loaded.

You forgot:=20
5) the compiler makes N versions of function if there are
notable differences between 'restrict' or no restrict and linker chooses
if to link copy() to one working like memcpy() or to one working like=20
memmove() on each case
I would prefer 1) on case of uncertainty and if the obvious 5) is unavailab=
le.

> While an optimizing linker could replace use of 'restrict' for
> statically linked function calls, it is unable to replacate it's
> effects when dynamic linking is used.

Dynamic linking involves mostly linking too. The case without any linking
is where some runtime string "goo.foo" is used as name for dynamic
module and a similarly dynamic function name  "poo" is searched from
it matched with some signature and called. On such cases most foam
goes to that meta-processing and the few instructions that 'restrict'
could save are hardly worth mentioning. So the version accessible that
way could be again the one that assumes that parameters can alias.=20
0
ootiib (965)
8/31/2012 1:40:56 AM
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 08/30/2012 06:18 PM, Jens Gustedt wrote:
> Am 30.08.2012 19:49, schrieb Garrett Hartshaw:
>> 'char *' says "this is a pointer to an object of type 'char'", 
>> 'unsigned char *' says "this is a pointer to an object of type 
>> 'unsigned char'", 'void *' says "this is a pointer to an object
>> of an unknown/any type".
> 
> no, at least for C "void" is a type, too.
> 
> The void type comprises an empty set of values; it is an
> incomplete object type that cannot be completed.
> 
> so "void*" says pointer to void. This is not "nothing" or
> "unknown", in that sense void is not much different from "struct
> nix" when you never actually define "struct nix" somewhere. It
> behaves a bit different in terms of implicit conversions, sure, but
> the sematic is the same.
> 
>> If you want to interpret an object as a sequence of bytes, then
>> use 'unsigned char *' or 'uint8_t *'. I see 'unsigned char' as
>> meaning a character in an encoding that is represented as an
>> 8-bit unsigned integer, while 'uint8_t' is an arbitrary 8-bit
>> unsigned integer. (e.g. I would write "unsigned char a = 'a'" and
>> "uint8_t b = 10", but not "unsigned char c = 10" or "uint8_t d =
>> 'd'")
>> 
>> If on the other hand you wish to have an opaque pointer to an
>> object of unknown type, or to an uninitialized memory region,
>> then use 'void *'.
> 
> A "void*" pointer is not "an uninitialized" memory region. It may
> well already be initialized.

As Keith said, that was meant to be how it should be used, rather than
exactly what it means to the compiler.

> 
> But I am really surprised about this strong need of opaque pointer
> in C++. If we follow the basic ideas of C++ such a usage should be
> very rare in C++, no? Isn't that what "abstract base classes" have
> been invented for?
> 
>> Even if 'void *' was redefined to mean 'unsigned char *', I
>> would still distinguish between their uses just as I distinguish
>> between 'unsigned char' and 'uint8_t'.
> 
> Therefore I had my question that came afterward and that you seem
> to have overlooked:
> 
>>> Would you be more comfortable if the standard introduced a
>>> type alias "byte" for "unsigned char"?
>> 
>>> That would completely be conceivable. For example C11
>>> introduces
>> 
>>> typedef int errno_t;
>> 
>>> but by reclaiming a different semantic for "errno_t" than for 
>>> "int".
> 
> The naming of "char" (and the two others) certainly doesn't cover
> all its uses that these type nowadays have, and it would be good to
> find semantic names for the different use cases.
> 
> typedef char byte_t;            // for the minimal addressable
> storage unit typedef unsigned char bitX_t;   // for an arbitrary
> collection of unspecific data, usually X == 8 typedef unsigned char
> uintX_t;  // for use as small unsigned integer, usually X == 8 
> typedef signed char intX_t;     // for use as small signed
> integer, usually X == 8
> 
> Jens
> 

One of the major uses of typedef is to allow this kind of
disambiguation between types that are represented identically. While I
don't often have need to work low-level directly on bytes, if I did I
would not hesitate to create a byte_t typedef, and if it was already
included in the standard, so much the better (although I would
probably typedef it as 'unsigned char' to avoid the
implementation-defined signed-ness of plain 'char').

However, even if 'byte_t' were added to the standard, I would still
want to distinguish between 'byte_t *' (used as a pointer to a byte)
and 'void *' (used as an opaque pointer or a pointer to uninitialized
memory) *even if they both meant the same thing to the compiler*.

Granted it would better for 'memcpy' and friends to use 'byte_t *'
rather than 'void *', as their underlying functionality is specified
in terms of moving/copying bytes. 'void *' would still be required *in
C* as the return value of 'malloc' (unitialized memory) and for use as
a userData parameter in callbacks (opaque pointer to an object of
unspecified type). There is little use for 'void *' in pure C++ code,
but it would still be required in the language to interface with C code.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.19 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJQQBxQAAoJEP8JewLaHvzSQJ0H+gNUnCggPWCdrovjjEDnANY0
mL2/5I+R+Ckn7sMYDWmdc6jhxQPcfoKX7aHT9C2DV1MWRfigMb4z0rsKqcc+WjUY
FJXEjLtlv9H+IHHuypXWNqVAPm7HgpXq74L/yhv2H2IlJqra6DW58ULdWRm6DUSN
xHijMzGpuNIw7LE3zzilinJfvP26+pxXZDuFmWXs2pCAPXgikZS1AG9PQWnVWXLz
DXDZ7nejxIc8FIesNfxO3NLzzMVZ69ZhyfB4M6UwCD2TdeRdrAYay5f3sEHKtIvG
N2RXXXV+J36ZX4w0i6dQuuCuAHzBaPwBcvtW79nIzgAv5pqlCDA4kuMl8WF1Y4s=
=SUbB
-----END PGP SIGNATURE-----
0
ghartshaw (25)
8/31/2012 2:07:12 AM
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 08/30/2012 09:40 PM, �� Tiib wrote:
> On Thursday, August 30, 2012 8:36:57 PM UTC+3, Garrett Hartshaw
> wrote:
>> On 08/30/2012 11:04 AM, �� Tiib wrote:
>>> On Wednesday, August 29, 2012 11:41:08 AM UTC+3, Jens Gustedt 
>>> wrote:
>>>> Am 29.08.2012 09:51, schrieb David Brown:
>>>>> On 28/08/2012 19:14, �� Tiib wrote:
>>>>>> As about keywords like 'restrict', 'inline' or 'register'
>>>>>> i am sure that on general case compiler and/or linker
>>>>>> can optimize lot better thanaverage Joe and so the
>>>>>> keywords just add pointless bloat.
>>>> 
>>>> I disagree with all of these points.
>>> 
>>> Nice. Then there is something to discuss i hope.
>> [snip]
>>>>> But it will be a long time before compiler technology can 
>>>>> figure out all cases of "restrict" by itself - that
>>>>> requires insight between different compile units, and hefty
>>>>> analysis on the way the functions are used.
>>>> 
>>>> This will never come, because the compiler simply can't
>>>> know. "restrict" is an interface specification that assures
>>>> the called function that this particular pointer doesn't
>>>> alias. This is an invariant that has to be checked at the
>>>> calling side and relied upon on the called side. There is no
>>>> general way to infer this at compile time if calling function
>>>> and called function are compiled separately.
>>> 
>>> Yes, compiler can't know. Ever heard of 'optimizing linker'?
>>> Yes such linker has to generate code too ... but so what?
>>> 
>> Ever heard of dynamic linking?
> 
> Certainly. It is part of our everyday work, despite neither
> language defines anything that matters in that respect.
> 
>> These are the options as I see them. 1) The compiler assumes that
>> the function can alias. 2) The compiler assumes that the function
>> cannot alias, optimizes based on this, and calls that do alias
>> are undefined bahavior and likely fail. 3) The compiler respects
>> the 'restrict' keyword. 4) The linker recompiles every library
>> when it is dynamically loaded.
> 
> You forgot: 5) the compiler makes N versions of function if there
> are notable differences between 'restrict' or no restrict and
> linker chooses if to link copy() to one working like memcpy() or to
> one working like memmove() on each case I would prefer 1) on case
> of uncertainty and if the obvious 5) is unavailable.
> 

Ah, I did miss that option.

Yes if it could be shown that compiler writers would be able to
(fairly) easily implement the ability to distinguish all calls of
memcpy() and memmove() (it would be pointless if this aliasing
detection go the way of the 'export' keyword and was never
implemented) then 5) would be indeed preferred. Failing this, I would
prefer 3) over 1), so that aliasing optimization can take place where
the programmer knows that it is safe.

>> While an optimizing linker could replace use of 'restrict' for 
>> statically linked function calls, it is unable to replacate it's 
>> effects when dynamic linking is used.
> 
> Dynamic linking involves mostly linking too. The case without any
> linking is where some runtime string "goo.foo" is used as name for
> dynamic module and a similarly dynamic function name  "poo" is
> searched from it matched with some signature and called. On such
> cases most foam goes to that meta-processing and the few
> instructions that 'restrict' could save are hardly worth
> mentioning. So the version accessible that way could be again the
> one that assumes that parameters can alias.
> 

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.19 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJQQB/GAAoJEP8JewLaHvzSYx4H/iv+6TKHr/M00tNZALekYtq4
+C5OP/Omiu7PrXDUhohurBDC3+MEFoFbFFELXrTW6MAghHcb1D5I4uCFtBShwiGS
joRjv4vpQ/wyhbv2fl2badawaMX1dSOFHWM3Z7xBFkCc/aljYgd2/EboSl54lsPw
guTjw/ML14y7/LR3ooagrMpYV9Jp6FJ29iH/98gt68ayWKfQECk60X5KeL6KyT9B
qJTsZyGsizyh6sYt56ljB77edRRqadGlHtNUWm318WuwHXaxmc62VGQq7qQfMlH7
cEN1kqdUuqwa52iBmTjDS2SQysu0wJFGWQArxy2eeOEyC5gqIy3F0khIwJlbPpI=
=iNeG
-----END PGP SIGNATURE-----
0
ghartshaw (25)
8/31/2012 2:21:58 AM
On Friday, August 31, 2012 1:39:08 AM UTC+3, Jens Gustedt wrote:
> Am 30.08.2012 17:04, schrieb =D6=F6 Tiib:
> > On Wednesday, August 29, 2012 11:41:08 AM UTC+3, Jens Gustedt wrote:
> > This is too subtle effect. If I want to forbid taking and storing=20
> > references or pointers to temporaries or locals then lot better is to
> > teach to people that it is bad idea, not use 'register' keyword
> > that has never been meant for that.
>=20
> Hm, this is a strong statement. It is the only observable impact that
> the register keyword has in C. BTW the concept of an "object that
> could have been declared with the register keyword" appears in C and
> makes an important difference for the status of uninitialized objects.

The keyword is used, in lot of code, certainly. I am not sure if it guards
against any errors or compiles as better binary. I can not recall when
that was a case and well placed register keyword saved the day.=20

> > Yes, compiler can't know. Ever heard of 'optimizing linker'? Yes such
> > linker has to generate code too ... but so what? =20
>=20
> Hm, you are telling me that an optimizing linker could be able to
> distinguish between "memcpy" and "memmove" and then would be able to
> link against the correct function? In any situation where an imaginary
> "copy" function is called it could distinguish at link time if the two
> memory regions overlap or not? Good to hear.

The compiler could somehow "mangle" the calls to indicate if the parameters
alias or not. If that is too hard for those two to decide then a human
maintainer would screw it up most of the time anyway.  There may be some
options (like attributes) made for rare power users.

> > Yes. Can you bring any example where you would want the diagnostic
> > because you put definition into header but forgot 'inline'? I can't.=20
> > So i would like implicit 'dontProduceMultipleSymbolErrors' for all
> > #included function definitions.
>=20
> You mean a function definition that comes from the inclusion of a .h
> file, I suppose. At least for the moment in C (and probably C++, too)
> there is no distinction into different types of source files.

There is #include directive in both languages and so it is easy to
say what "file has been included". No strict file type differentiation
is needed.

> An function definition that is generated by a macro, would be
> accounted in which class?

Depending on where that macro expands. Note that what C++ linker
does with instantiated function templates is far more fascinating. The
compiler may prepare lots of copies but linker somehow mops them
together and executable is still quite small. Implicit inline would be
no problem at all.=20
0
ootiib (965)
8/31/2012 3:48:51 AM
On 31/08/2012 05:48, �� Tiib wrote:

> The compiler could somehow "mangle" the calls to indicate if the parameters
> alias or not. If that is too hard for those two to decide then a human
> maintainer would screw it up most of the time anyway.  There may be some
> options (like attributes) made for rare power users.
>

There is a vast amount of information that the compiler could 
"communicate" between two object files to improve code optimisation - an 
implicit "restrict" is only one possibility.

Unfortunately, C and C++ compilers of today do not have a workable 
mechanism for such things.

Much can be achieved with a "compile everything in one go" workflow. 
But that is only suitable for a small number of cases (in particular, 
for small programs where there is complete access to all source code, 
including libraries).

Link-time optimisations are a step in between, and allow some of this. 
But it is a great challenge to tool vendors to make it work efficiently 
with large programs.  And anything involving outside object code (such 
as libraries compiled with a different version of the toolchain) break 
such optimisation opportunities.


We need to either go back 30 years and define new details in object 
files and a new "compiled header" format, or wait another 10 years and 
hope for a consensus on LTO formats, and more powerful computers.

In the mean time, we can use "restrict" and things like "pure" and 
"const" function attributes.

0
david2384 (2168)
8/31/2012 8:50:50 AM
On 30/08/2012 16:13, �� Tiib wrote:
> On Wednesday, August 29, 2012 10:51:59 AM UTC+3, David Brown wrote:
>> On 28/08/2012 19:14, �� Tiib wrote:
>>> static_assert about sizeof guarantees that it won't compile. For
>>> bit order and padding you need bit more complex static asserts.
>>
>> Yes, I use static_assert to check all these things.  Once I get to
>> use newer C (or C++) standards with real static_assert, I'll be
>> happy.  At the moment, I use macros that end up causing errors
>> (arrays with negative sizes) on assertion failures - they are
>> messy, and give weird error messages if they are triggered, but
>> they are a great help anyway.
>
> So it just takes time, but standards have already given us a tool
> that mitigates most problems with bit order, byte count and padding.
>

No, the standards have not given us such a tool.  They have made it a 
little easier to check for problems (which is nice), but they have done 
nothing towards avoiding or mitigating those problems.

If you take your car to the workshop because of an oil leak, you want 
them to fix the oil leak.  You will not be happy about a nicer coloured 
light indicating that a leak has occurred.


>>> As about keywords like 'restrict', 'inline' or 'register' i am
>>> sure that on general case compiler and/or linker can optimize lot
>>> better thanaverage Joe and so the keywords just add pointless
>>> bloat.
>>
>> But it will be a long time before compiler technology can figure
>> out all cases of "restrict" by itself - that requires insight
>> between different compile units, and hefty analysis on the way the
>> functions are used.
>
> I feel that every time the standards drop some optimization on our
> shoulders they have later to take it away. Joes create a mess with it
> that does not compile or makes some compiler to lose in competition.
> 'inline' is only hint now (at least in C++) and both its presence and
> lack does guarantee nothing.

You never have /any/ guarantees about optimisations (or lack thereof) in 
C or C++.  Compilers can generate whatever code they want - good or bad 
- as long as the end result acts correctly.

But good programmers are smarter than compilers.  They know things that 
the compiler cannot figure out for itself.  And while compiler 
technology has undoubtedly been getting smarter, this is still true.  So 
advanced programmers need the tools, like "restrict", to get the best code.

And yes, things change.  Long ago, it made sense to use "register" 
because it helped the compiler.  It also used to make sense to use 
pointer code rather than array code to generate better object code - 
while now compilers will generally do better with the array code.  But 
saying that one day compilers will be good enough to figure out 
"restrict" cases themselves is no reason not to have it now!

>
>> Similarly with "inline" - the compiler can figure out many
>> functions that should be inlined, but certainly not all.  There are
>> plenty of situations when the programmer knows that inlining a
>> function will be very efficient (perhaps due to constant folding),
>> but the compiler thinks the function is too large.  Compilers are
>> getting better at this (at least, gcc is), but they are not yet
>> omnipotent.  And there are situations where the programmer might
>> want to disable automatic inlining (to make debugging easier), but
>> still want some functions inlined - using the keyword explicitly
>> gives that control.
>
> Things that guarantee something i love. Does 'restrict' guarantee
> some different behavior? Then i take my words back ... then it
> should be keyword in C++ as well. I had impression that it was
> another "maybe optimize" feature like 'register' and 'inline'. Then
> compiler could generate versions with restrict and without if it
> matters and linker could just choose and maybe inline instead.

Compilers cannot "generate versions with and without restrict" - if you 
have a function with a half-dozen pointers, is it supposed to generate 
64 different variations?

"restrict" /is/ a guarantee - but it is a guarantee from the 
programmer's side, not the compiler's.  It tells the compiler that the 
programmer will never use the code with overlapping pointers or aliases. 
  The compiler can use this information to generate better code, or it 
can ignore it.

>
>> Perhaps I don't count as an "average Joe"...
>
> For senior developer there should be standardized something that
> guarantee certain optimizations or turn them off like gcc attributes
> noinline and always_inline. The syntax must be really ugly so average
> Joe can see that it is senior developer's feature from far. Exactly
> like gcc has.
>
> You are still probably more efficient (i am) when ganging up with
> others and you have to be tolerant with them, everybody start as
> sub-average Joes.
>
> Why do not they make 'inline' not mandatory for function definition
> in include file as well? Make a logic that if file is #included then
> function definition in it is implicitly 'inline' and let the
> compiler and linker to decide what really happens (they anyway do).
> That would remove all usage of 'inline' and Joes (and me) would be
> more happy.
>

If you understand how C and C++ work with the pre-processor and 
#include, then you can easily see why such a rule is impossible.  There 
is no way the compiler can distinguish between #include'd code and code 
in the main .c or .cpp file.  In particular, anything that can go in a 
"header" can also go directly in the "source" file, and some people 
#include source files in their main file.  This is common practice with 
C++ - as a way to get control over the order of creation of global 
objects, people write a C++ file "all.cpp" which #include's all the 
other .cpp files in the project.  (Obviously I disapprove of this 
practice - but people do it.)

To get the effects you want here, you need to move to languages like Ada 
or Modula 2 that have a clear separation between "interface" and 
"implementation" files.
0
david2384 (2168)
8/31/2012 9:06:27 AM
On 30/08/2012 23:07, Keith Thompson wrote:
> Garrett Hartshaw <ghartshaw@gmail.com> writes:
> [...]
>> If you want to interpret an object as a sequence of bytes, then use
>> 'unsigned char *' or 'uint8_t *'. I see 'unsigned char' as meaning a
>> character in an encoding that is represented as an 8-bit unsigned
>> integer, while 'uint8_t' is an arbitrary 8-bit unsigned integer. (e.g.
>> I would write "unsigned char a = 'a'" and "uint8_t b = 10", but not
>> "unsigned char c = 10" or "uint8_t d = 'd'")
> [...]
>
> Strictly speaking, `unsigned char *` and `uint8_t *` are not
> interchangeable.  `unsigned char` is one byte by definition.
> `uint8_t` is 8 bits by definition -- and if CHAR_BIT > 8, then
> `uint8_t` will not exist.
>
> C's treatment of characters is a bit of a mess IMHO, partly due to
> changes in character semantics since C was first defined.  When we
> could assume 7-bit ASCII (or 8-bit EBCDIC with plain char being
> unsigned), C's model worked.  With the introduction of ASCII-based
> 8-bit character representations, with plain char remaining signed
> on many systems, things started getting confusing.
>
> Conflating the concepts of a single character and a single
> fundamental storage unit into the types `char`, `signed char`, and
> `unsigned char`, all required to be the same size, no longer makes
> as much sense now as it did then.
>
> If I were designing a C-like language from scratch today, I'd
> separate the concepts of characters and fundamental storage units.
> I'd probably also separate the concept of very short integers
> from both.  So `char`, `byte`, and `int8` might be three distinct
> and incompatible types.
>
> Making such a change to C now would break so much code that the
> resulting language could not reasonably be called "C"; it ain't
> gonna happen.
>

This is pretty much exactly what Python did with Python 3.  Previously, 
strings and characters were also used as raw data - now they are 
separate types.  But I agree that it is not going to happen in C.

I would be happy with a "byte" being officially defined as the type for 
memory units, however.  Maybe "data8_t" would be more appropriate - then 
we could have "data16_t", etc., as well.

0
david2384 (2168)
8/31/2012 9:13:26 AM
On 30/08/2012 19:57, James Kuyper wrote:
> On 08/30/2012 08:54 AM, David Brown wrote:
>> On 30/08/2012 14:05, James Kuyper wrote:
>>> On 08/30/2012 03:47 AM, David Brown wrote:
>>>> On 29/08/2012 20:34, James Kuyper 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?
>>>>>
>>>>
>>>> You skipped the important part of Leigh's post - "char* is .. wait for
>>>> it .. a pointer to char; void* is .. wait for it .. a pointer to
>>>> anything; this has not changed from C to C++."
>>>>
>>>> If you write in your code "char* p", you are saying that "p is a pointer
>>>> to a character or a list of characters".  If you write "void* p", you
>>>> are saying that "p points to something which could be anything".
>>>
>>> Yes, I skipped that, because I considered it an unimportant and silly
>>> distinction. It's the functional differences between char* and void*
>>> that render void* the appropriate way to store a pointer of unknown
>>> type; remove those functional differences, and I wouldn't bother using
>>> 'void*' rather than 'char*' just because 'void*' documents a supposedly
>>> different meaning. My point being that C++ lacks some (though not yet
>>> all) of the functional differences that C has between those two types.
>>>
>>>> These are different things.  It really doesn't matter how these are
>>>> implemented, and what casts can be done implicitly or explicitly - they
>>>> /say/ different things.
>>>
>>> If they were functionally equivalent, the fact that they had different
>>> names wouldn't mean that they actually say anything different, however
>>> much you might want to think otherwise.
>>>
>>
>> That is obviously incorrect.  A comment is functionally equivalent to
>> white space - are you suggesting that comments do not "say" anything in
>> source code?
>
> Comments are for talking with other humans; the active part of the
> language is for talking to the compiler.

The active part of the language is for talking to the compiler /and/ 
humans.  That is the reason we have typedefs, and the reason we give 
variables useful names rather than "i1", "i2", etc.

> If the differences, for the
> compiler, between 'void*' and 'char*' were reduced to a matter of how
> they were spelled, I would not recommend using that spelling to convey
> meaningful information to any humans who were reading the code.

If you don't think "void*" and "char*" convey a different meaning to 
humans, then I see your point.  IMHO, they /do/ convey a different 
meaning - so they have different usage even if they had identical 
functional meaning.

>
> This assertion is somewhat inconsistent with the fact that I have chosen
> to use distinctions between other equivalent constructs to convey actual
> meanings. For instance, when writing function declarations in C, I use T
> *parameter_name to represent a pointer to a single object, and T
> parameter_name[] when it is a pointer to the first in a series of
> objects (in C++ I would use a reference for the first purpose).
>
> I'll not bother to try and excuse the inconsistency; I'll just say that
> the pointer parameter thing feels harmless to me, whereas I feel a
> strong antipathy about removing the distinctions between void* and char*
> (I really dislike the gnu extension that allows pointer arithmetic on
> void*).
>

There is nothing wrong with a bit of inconsistency here and there - you 
don't want your style rules to be /too/ rigid!

0
david2384 (2168)
8/31/2012 9:27:28 AM
On Friday, August 31, 2012 11:51:45 AM UTC+3, David Brown wrote:
> We need to either go back 30 years and define new details in object 
> files and a new "compiled header" format, or wait another 10 years and 
> hope for a consensus on LTO formats, and more powerful computers.

All the compiler vendors participate in standardization and yet they can
not come up with solutions that open new ways for their tools to compete
with each other. Instead of that they add another keyword. Are you serious
that object files format is exactly like it was 1982 (30 years ago)?

0
ootiib (965)
8/31/2012 11:58:14 AM
On 31/08/2012 13:58, �� Tiib wrote:
> On Friday, August 31, 2012 11:51:45 AM UTC+3, David Brown wrote:
>> We need to either go back 30 years and define new details in object
>> files and a new "compiled header" format, or wait another 10 years and
>> hope for a consensus on LTO formats, and more powerful computers.
>
> All the compiler vendors participate in standardization and yet they can
> not come up with solutions that open new ways for their tools to compete
> with each other. Instead of that they add another keyword. Are you serious
> that object files format is exactly like it was 1982 (30 years ago)?
>

There are minor differences in details (and huge differences for debug 
formats), but most compilers have much the same information in object 
files as they always have.

Some compilers - especially more specialised embedded development tools 
- do things a bit differently.

0
david2384 (2168)
8/31/2012 12:23:32 PM
Am 31.08.2012 04:07, schrieb Garrett Hartshaw:

> Granted it would better for 'memcpy' and friends to use 'byte_t *'
> rather than 'void *', as their underlying functionality is specified
> in terms of moving/copying bytes. 'void *' would still be required *in
> C* as the return value of 'malloc' (unitialized memory) and for use as
> a userData parameter in callbacks (opaque pointer to an object of
> unspecified type).

Perhaps this got a bit lost in the discussion, but all of that started
by trying to find replacements for "void*" in C++.

"void*" is a concept that works suitably well in C. It is just a
nuisance in C++.

> There is little use for 'void *' in pure C++ code,
> but it would still be required in the language to interface with C code.

Sure that was my starting point.

I even think that in C++ all conversion from "void*" to another type
should and could be avoided. Basically I would say code that uses
"void*" (manipulating pointers to void, or obfuscating types) are "C
in disguise".

I haven't heard of a good C++ use case, yet, that couldn't be packed
into an 'extern "C"' interface and where the implementation then
couldn't be done in proper C. A bit in the same spirit as some
specific functions for OS or compilers are implemented in assembler.

Jens


0
8/31/2012 12:53:53 PM
On Aug 30, 9:17=A0am, Jens Gustedt <jens.gust...@loria.fr> wrote:
> Am 30.08.2012 09:47, schrieb David Brown:
> > On 29/08/2012 20:34, James Kuyper wrote:
> >> On 08/29/2012 02:16 PM, Leigh Johnston wrote:

<snip>

> > If you write in your code "char* p", you are saying that "p is a pointe=
r
> > to a character or a list of characters". =A0If you write "void* p", you
> > are saying that "p points to something which could be anything".
>
> > These are different things. =A0It really doesn't matter how these are
> > implemented, and what casts can be done implicitly or explicitly - they
> > /say/ different things. =A0Your compiler will spend milliseconds readin=
g
> > your code, and doesn't care about style, logic, or readability. =A0But
> > programmers might spend days reading it or writing it, and they might
> > need to do so again after years have passed. =A0This is why you write c=
ode
> > that says what it should say. =A0This is why you never use an "unsigned
> > char" to store a small number, but rather use an "uint8_t" - it does
> > exactly the same thing, but makes the purpose clear.

 ugly though

> You probably didn't see my reply to that either, this thread got
> somehow out of bounds.
>
> You just should push the button a bit further where Leigh stopped. He
> resolved the term "void" but didn't for "char". "char" is the smallest
> addressable unit in C and C++ (Pascal had byte for that, no)

no. Pascal did not have a byte type

> that is
> almost completely stripped of a semantic interpretation.
>
> Traditionally "char*" was also that, a pointer to a region of
> unspecific bytes. Nowadays "unsigned char*" serves that purpose,
> because it has the advantage of letting you access any bit (!) and
> bite of the data and you'd don't have confusion with the other
> completely orthogonal use of "char*" for C strings.

which is why I use a byte or octet typedef

> Semantically I don't see much difference with that respect between
> "void*" and "unsigned char*". Both are pointers to unspecific
> data. They have different properties, sure, one of my interest in this
> thread was to know about what properties people actually use. (And
> from the C++ side I only got partial answers, yet.)
>
> And you are completely right with your argument that small numbers
> that are meant as such should use "uint8_t" or similar and not
> "unsigned char". Generally, in C you should use the semantic
> predefined typedef's as much as possible to mark your intent with a
> particular data.
0
8/31/2012 12:59:44 PM
On Friday, August 31, 2012 12:07:23 PM UTC+3, David Brown wrote:
> On 30/08/2012 16:13, =D6=F6 Tiib wrote:
> > So it just takes time, but standards have already given us a tool
> > that mitigates most problems with bit order, byte count and padding.
> >
>=20
> No, the standards have not given us such a tool.  They have made it a=20
> little easier to check for problems (which is nice), but they have done=
=20
> nothing towards avoiding or mitigating those problems.

The few cases when the bit orders byte counts and padding does
matter are all related to communicating with other hardware or software
using some intermediate media where bits are defined by a protocol or
file format. If compiler indicates problem then it is easy to modify.

> If you take your car to the workshop because of an oil leak, you want=20
> them to fix the oil leak.  You will not be happy about a nicer coloured=
=20
> light indicating that a leak has occurred.

My software is all less and less written by me. There are libraries and oth=
er
libraries that use the libraries. My code is more and more like picking
configuration of the libraries and some other thin layer of clue here
and there. Still ... i do not see it as a car made by someone else.
The static_assert is written by me as well, where should compiler
know that bit order matters when i am taking data out of some
byte buffer.

> You never have /any/ guarantees about optimisations (or lack thereof) in=
=20
> C or C++.  Compilers can generate whatever code they want - good or bad=
=20
> - as long as the end result acts correctly.

That is true. Also the runtime libraries for some exotic embedded platform
may contain outright awfully performing functions. When it matters then
replace and  rewrite. That is our part of the business.

> But good programmers are smarter than compilers.  They know things that=
=20
> the compiler cannot figure out for itself.  And while compiler=20
> technology has undoubtedly been getting smarter, this is still true.  So=
=20
> advanced programmers need the tools, like "restrict", to get the best cod=
e.

'memcpy()' and 'memmove()' did coexist long before 'restrict'.

> And yes, things change.  Long ago, it made sense to use "register"=20
> because it helped the compiler.  It also used to make sense to use=20
> pointer code rather than array code to generate better object code -=20
> while now compilers will generally do better with the array code.  But=20
> saying that one day compilers will be good enough to figure out=20
> "restrict" cases themselves is no reason not to have it now!

It still is that if a compiler could issue diagnostic that you are
misusing function with restrict then it could pick better candidate itself.
If the restrict would give any opportunities to optimize or none
is also better known to compiler that might do those optimizations.

> Compilers cannot "generate versions with and without restrict" - if you=
=20
> have a function with a half-dozen pointers, is it supposed to generate=20
> 64 different variations?

If it really matters then why not? There are gigabytes of memory and=20
terabytes of other storage even in modern laptops.=20

> > Why do not they make 'inline' not mandatory for function definition
> > in include file as well? Make a logic that if file is #included then
> > function definition in it is implicitly 'inline' and let the
> > compiler and linker to decide what really happens (they anyway do).
> > That would remove all usage of 'inline' and Joes (and me) would be
> > more happy.
> >
>=20
> If you understand how C and C++ work with the pre-processor and=20
> #include, then you can easily see why such a rule is impossible.  There=
=20
> is no way the compiler can distinguish between #include'd code and code=
=20
> in the main .c or .cpp file.  In particular, anything that can go in a=20
> "header" can also go directly in the "source" file, and some people=20
> #include source files in their main file.  This is common practice with=
=20
> C++ - as a way to get control over the order of creation of global=20
> objects, people write a C++ file "all.cpp" which #include's all the=20
> other .cpp files in the project.  (Obviously I disapprove of this=20
> practice - but people do it.)

So they would get everything implicitly 'inline'. That would hopefully
cause them to drop that odd practice and so they become better
people and easier to cooperate with. :-)
=20
> To get the effects you want here, you need to move to languages like Ada=
=20
> or Modula 2 that have a clear separation between "interface" and=20
> "implementation" files.

I did not even want to get started with that. Code bases with several milli=
ons
lines are quite common but no support in the language whatsoever for
modular architecture. No. I just said that 'inline' is pointless.

0
ootiib (965)
8/31/2012 1:05:53 PM
=?ISO-8859-1?Q?=D6=F6_Tiib?= <ootiib@hot.ee> writes:
>On Friday, August 31, 2012 1:39:08 AM UTC+3, Jens Gustedt wrote:
>> Am 30.08.2012 17:04, schrieb =D6=F6 Tiib:
>> > On Wednesday, August 29, 2012 11:41:08 AM UTC+3, Jens Gustedt wrote:
>> > This is too subtle effect. If I want to forbid taking and storing=20
>> > references or pointers to temporaries or locals then lot better is to
>> > teach to people that it is bad idea, not use 'register' keyword
>> > that has never been meant for that.
>>=20
>> Hm, this is a strong statement. It is the only observable impact that
>> the register keyword has in C. BTW the concept of an "object that
>> could have been declared with the register keyword" appears in C and
>> makes an important difference for the status of uninitialized objects.
>
>The keyword is used, in lot of code, certainly. I am not sure if it guards
>against any errors or compiles as better binary. I can not recall when
>that was a case and well placed register keyword saved the day.=20

Back in the 70's, when I was using C on a PDP-11 running unix V6, the
register keyword was quite useful;   the PDP-11 had 8 registers (r0 - r7),
where R6 was the stack pointer and R7 was the Program Counter.  The
register keyword would tell the compiler (whose optimizer was primitive,
to say the least) to attempt to keep a variable qualified with the
register keyword in one of the registers, rather than spilling to the
stack.   The compiler was free to ignore the 'hint'.   It certainly had
a positive effect on performance absent modern optimization passes.

With modern optimizing compilers, the register keyword is generally ignored.

scott
0
scott1 (423)
8/31/2012 2:18:28 PM
Nick Keighley <nick_keighley_nospam@hotmail.com> writes:
>On Aug 30, 9:17=A0am, Jens Gustedt <jens.gust...@loria.fr> wrote:
>
>> You just should push the button a bit further where Leigh stopped. He
>> resolved the term "void" but didn't for "char". "char" is the smallest
>> addressable unit in C and C++ (Pascal had byte for that, no)
>
>no. Pascal did not have a byte type

Well, perhaps not in the "standard", but it was a common extension:

e.g. VAX Pascal:

[INHERIT('SYS$SHARE:STARLET'),
 IDENT('V03-001')]

PROGRAM Users( OUTPUT );

TYPE
  Unsigned_byte = [BYTE] 0..255;
  Signed_word   = [WORD] -32768..+32767;
  Unsigned_word = [WORD] 0..65535;

  jpi$item      = [BYTE(12)] PACKED RECORD
        Buffer_length:  [POS(0)] Unsigned_word;
        Item_code:      [POS(16)] Unsigned_word;
        Buffer_address: [POS(32),LONG,UNSAFE] UNSIGNED;
        Buflen_address: [POS(64),LONG,UNSAFE] UNSIGNED;
  END;

  Terminfo_rec  = [BYTE(80)] RECORD
        Csp_id:         [BYTE(04),POS(0),KEY(0)] PACKED ARRAY [1..04] OF CHAR;
        Junk:           [BYTE(27)] PACKED ARRAY [1..27] OF CHAR;
        Short:          [BYTE(09)] PACKED ARRAY [1..09] OF CHAR;
        Long:           [BYTE(21)] PACKED ARRAY [1..21] OF CHAR;
        Csp_long:       [BYTE(07)] PACKED ARRAY [1..07] OF CHAR;
        Filler:         [BYTE(12)] PACKED ARRAY [1..12] OF CHAR;
  END;

  Csp_stat_rec  = [LONG] PACKED RECORD
        Ss_status:      [POS(00)] Unsigned_word;
        Port:           [POS(16)] Unsigned_byte;
        Machine:        [POS(24)] Unsigned_byte;
  END;

0
scott1 (423)
8/31/2012 2:29:02 PM
On 8/30/2012 4:07 PM, Keith Thompson wrote:
> Garrett Hartshaw <ghartshaw@gmail.com> writes:
> [...]
>> If you want to interpret an object as a sequence of bytes, then use
>> 'unsigned char *' or 'uint8_t *'. I see 'unsigned char' as meaning a
>> character in an encoding that is represented as an 8-bit unsigned
>> integer, while 'uint8_t' is an arbitrary 8-bit unsigned integer. (e.g.
>> I would write "unsigned char a = 'a'" and "uint8_t b = 10", but not
>> "unsigned char c = 10" or "uint8_t d = 'd'")
> [...]
>
> Strictly speaking, `unsigned char *` and `uint8_t *` are not
> interchangeable.  `unsigned char` is one byte by definition.
> `uint8_t` is 8 bits by definition -- and if CHAR_BIT > 8, then
> `uint8_t` will not exist.
>
> C's treatment of characters is a bit of a mess IMHO, partly due to
> changes in character semantics since C was first defined.  When we
> could assume 7-bit ASCII (or 8-bit EBCDIC with plain char being
> unsigned), C's model worked.  With the introduction of ASCII-based
> 8-bit character representations, with plain char remaining signed
> on many systems, things started getting confusing.
>
> Conflating the concepts of a single character and a single
> fundamental storage unit into the types `char`, `signed char`, and
> `unsigned char`, all required to be the same size, no longer makes
> as much sense now as it did then.
>
> If I were designing a C-like language from scratch today, I'd
> separate the concepts of characters and fundamental storage units.
> I'd probably also separate the concept of very short integers
> from both.  So `char`, `byte`, and `int8` might be three distinct
> and incompatible types.
>

my own language (BGBScript) more or less does this.


char is 16-bits (more-or-less, 1), byte is 8-bits unsigned, and sbyte is 
8-bits signed.

'int8' is also a type but is essentially an alias to sbyte.
'char8' also exists as an 8-bit character (also a distinct type, and is 
mostly intended for ASCII).

1: char is often interpreted as a single UTF-16 codepoint for storage 
reasons, but may often be 24-bit internally, and strings may often be 
stored using UTF-8 to save space (and still tend to be null-terminated, 
note that this can emulate the external behavior of a length-bound 
UTF-16 string, but on-average uses around 1/2 as much memory).


> Making such a change to C now would break so much code that the
> resulting language could not reasonably be called "C"; it ain't
> gonna happen.
>

yep.

it is about like the issues of making C be based on a module-import 
system (rather than including headers and linking objects into 
binaries), and generating target neutral VM bytecode. maybe it can be 
done, theoretically, but it is not likely an easy task to do so without 
violating the standards (or at least adding some fairly ugly extensions).


0
cr88192355 (1928)
8/31/2012 3:55:44 PM
On 8/31/2012 4:27 AM, David Brown wrote:
> On 30/08/2012 19:57, James Kuyper wrote:
>> On 08/30/2012 08:54 AM, David Brown wrote:
>>> On 30/08/2012 14:05, James Kuyper wrote:
>>>> On 08/30/2012 03:47 AM, David Brown wrote:
>>>>> On 29/08/2012 20:34, James Kuyper 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?
>>>>>>
>>>>>
>>>>> You skipped the important part of Leigh's post - "char* is .. wait for
>>>>> it .. a pointer to char; void* is .. wait for it .. a pointer to
>>>>> anything; this has not changed from C to C++."
>>>>>
>>>>> If you write in your code "char* p", you are saying that "p is a
>>>>> pointer
>>>>> to a character or a list of characters".  If you write "void* p", you
>>>>> are saying that "p points to something which could be anything".
>>>>
>>>> Yes, I skipped that, because I considered it an unimportant and silly
>>>> distinction. It's the functional differences between char* and void*
>>>> that render void* the appropriate way to store a pointer of unknown
>>>> type; remove those functional differences, and I wouldn't bother using
>>>> 'void*' rather than 'char*' just because 'void*' documents a supposedly
>>>> different meaning. My point being that C++ lacks some (though not yet
>>>> all) of the functional differences that C has between those two types.
>>>>
>>>>> These are different things.  It really doesn't matter how these are
>>>>> implemented, and what casts can be done implicitly or explicitly -
>>>>> they
>>>>> /say/ different things.
>>>>
>>>> If they were functionally equivalent, the fact that they had different
>>>> names wouldn't mean that they actually say anything different, however
>>>> much you might want to think otherwise.
>>>>
>>>
>>> That is obviously incorrect.  A comment is functionally equivalent to
>>> white space - are you suggesting that comments do not "say" anything in
>>> source code?
>>
>> Comments are for talking with other humans; the active part of the
>> language is for talking to the compiler.
>
> The active part of the language is for talking to the compiler /and/
> humans.  That is the reason we have typedefs, and the reason we give
> variables useful names rather than "i1", "i2", etc.
>

(partial ironic satire):

but what if i, j, and k are already used up?
i0/i1/i2/i3, j0/j1/j2/j3, and k0/k1/k2/k3, can effectively get 4x (or 
5x) as many integer-variables from the same letters...

then there may be {li/lj/lk}{0/1/2/3} for long-long variables, 
{a/b/c/d}{0/1/2/3} for doubles, {f/g/h}{0/1/2/3} for floats, ...


>> If the differences, for the
>> compiler, between 'void*' and 'char*' were reduced to a matter of how
>> they were spelled, I would not recommend using that spelling to convey
>> meaningful information to any humans who were reading the code.
>
> If you don't think "void*" and "char*" convey a different meaning to
> humans, then I see your point.  IMHO, they /do/ convey a different
> meaning - so they have different usage even if they had identical
> functional meaning.
>

in a lot of GCC compiled code, they are not too far off.
me remembering sometimes porting code from GCC and having to often 
convert "void *" to "byte *" (typedef'ed "unsigned char") or similar to 
make it work.


>>
>> This assertion is somewhat inconsistent with the fact that I have chosen
>> to use distinctions between other equivalent constructs to convey actual
>> meanings. For instance, when writing function declarations in C, I use T
>> *parameter_name to represent a pointer to a single object, and T
>> parameter_name[] when it is a pointer to the first in a series of
>> objects (in C++ I would use a reference for the first purpose).
>>
>> I'll not bother to try and excuse the inconsistency; I'll just say that
>> the pointer parameter thing feels harmless to me, whereas I feel a
>> strong antipathy about removing the distinctions between void* and char*
>> (I really dislike the gnu extension that allows pointer arithmetic on
>> void*).
>>
>
> There is nothing wrong with a bit of inconsistency here and there - you
> don't want your style rules to be /too/ rigid!
>

better IMO to be like "whatever makes the most sense at the moment".

as long as there is at least some semblance of consistency, then it is 
probably good enough.


0
cr88192355 (1928)
8/31/2012 4:58:58 PM
On 8/30/2012 8:30 PM, Keith Thompson wrote:
> Jens Gustedt <jens.gustedt@loria.fr> writes:
[...]
>> so "void*" says pointer to void. This is not "nothing" or "unknown",
>> in that sense void is not much different from "struct nix" when you
>> never actually define "struct nix" somewhere. It behaves a bit
>> different in terms of implicit conversions, sure, but the sematic is
>> the same.
>
> Not really.  A `char*` pointer points to an object of type `char`.  A
> `void*` pointer does not point to an object of type `void`, because
> there is no such thing.
>
> Any type of pointer to object or incomplete type (i.e., any pointer
> other than a function pointer) points to some object in memory (or to
> nothing if it's currently a null pointer).  What's special about `void*`
> is that, while you can perform certain pointer operations on it, you
> can't access the object it points to without first converting it to some
> other pointer type.
[...]

While technically correct that "void *" doesn't point to an object of type 
"void" because there's no such thing, I think it is convenient to think of 
it in those terms.

Consider, for example:

     struct IncompleteType;
     typedef struct IncompleteType MyVoid;

In this case, "MyVoid *" is kind of like "void *", as long as struct 
IncompleteType is never "completed".

Of course, there are differences:

     "void *" can be converted to/from any other data pointer type without
     the need for a cast.

     You are guaranteed that you can convert to "void *" and back, without
     the loss of any data.

As I said, it is technically correct that "void *" cannot point to something 
of type "void", because there is no such thing.  (You can't have an object 
of type "struct IncompleteType" in my example, either.)  However, I do think 
it's a convenient way to think of it, since any other "X *" would be a 
pointer to something of type "X".

P.S.  I see that this is crossposted to clc++.  I don't know C++ well enough 
to know if all of the above is true.  I do understand that you can't convert 
to/from "void *" in C++ without a cast.

-- 
Kenneth Brody
0
kenbrody (1879)
8/31/2012 6:18:10 PM
On 31/08/2012 19:18, Kenneth Brody wrote:
> On 8/30/2012 8:30 PM, Keith Thompson wrote:
>> Jens Gustedt <jens.gustedt@loria.fr> writes:
> [...]
>>> so "void*" says pointer to void. This is not "nothing" or "unknown",
>>> in that sense void is not much different from "struct nix" when you
>>> never actually define "struct nix" somewhere. It behaves a bit
>>> different in terms of implicit conversions, sure, but the sematic is
>>> the same.
>>
>> Not really.  A `char*` pointer points to an object of type `char`.  A
>> `void*` pointer does not point to an object of type `void`, because
>> there is no such thing.
>>
>> Any type of pointer to object or incomplete type (i.e., any pointer
>> other than a function pointer) points to some object in memory (or to
>> nothing if it's currently a null pointer).  What's special about `void*`
>> is that, while you can perform certain pointer operations on it, you
>> can't access the object it points to without first converting it to some
>> other pointer type.
> [...]
>
> While technically correct that "void *" doesn't point to an object of
> type "void" because there's no such thing, I think it is convenient to
> think of it in those terms.
>
> Consider, for example:
>
>      struct IncompleteType;
>      typedef struct IncompleteType MyVoid;
>
> In this case, "MyVoid *" is kind of like "void *", as long as struct
> IncompleteType is never "completed".
>
> Of course, there are differences:
>
>      "void *" can be converted to/from any other data pointer type without
>      the need for a cast.
>
>      You are guaranteed that you can convert to "void *" and back, without
>      the loss of any data.
>
> As I said, it is technically correct that "void *" cannot point to
> something of type "void", because there is no such thing.  (You can't
> have an object of type "struct IncompleteType" in my example, either.)
> However, I do think it's a convenient way to think of it, since any
> other "X *" would be a pointer to something of type "X".
>
> P.S.  I see that this is crossposted to clc++.  I don't know C++ well
> enough to know if all of the above is true.  I do understand that you
> can't convert to/from "void *" in C++ without a cast.

In C++ you can convert to void* without a cast.

/Leigh

0
leigh (1128)
8/31/2012 6:34:26 PM
On 2012-08-29 21:33, Bo Persson wrote:
> David Brown wrote 2012-08-29 09:51:
>
>> But it will be a long time before compiler technology can figure out all
>> cases of "restrict" by itself - that requires insight between different
>> compile units, and hefty analysis on the way the functions are used.
>>
>
> The argument from the C++ camp, for not implementing it, is that it is a
> lot less useful in C++. Most functions don't take pointers to basic
> types as parameters, because C++ is largely class based.
>
> Type based alias analysis will show that function parameters cannot
> alias, because they are of different class types. Adding restrict will
> not help.
>
> If you have
>
> void f(std::vector<int>& v1, std::vector<int>& v2)
> {
>     // Here v1[1] can never, ever alias v2[2]
>     // because vectors don't work that way, and the compiler can tell
> }
>
> on the other hand, with C style code
>
> void f(int* v1, int* v2)
> {
>     // Here any v1[i] might alias any v2[j]
>     // because the function just COULD have been called
>     // with f(p, p + 7)
>
> }

Of course, you are dead wrong. The two vectors can potentially alias 
(the compiler will have a really hard time proving otherwise, it would 
have to be able to track the underlying storage over the entire 
lifetime; neither Visual C++ nor GCC get it right, even in trivial cases).

Let's see:
#include <vector>
void test1(std::vector<int>& v1, std::vector<int>& v2) {
     v1[7] += 7;
     v2[3] = 10;
     v1[7] += 42;
}

void test2(int* v1, int* v2) {
     v1[7] += 7;
     v2[3] = 10;
     v1[7] += 42;
}

void test3(int* __restrict v1, int* __restrict v2) {
     v1[7] += 7;
     v2[3] = 10;
     v1[7] += 42;
}

The conclusion from the disassembly below: GCC and Visual C++ think that:
- test1(): the vectors can alias
- test2(): the pointers can alias
- test3(): the pointers can't alias

---- Visual C++ 2012 --------------------------------------------------
?test1@@YAXAAV?$vector@HV?$allocator@H@std@@@std@@0@Z (void __cdecl 
test1(class std::vector<int,class std::allocator<int> > &,class 
std::vector<int,class std::allocator<int> > &)):
   00000000: 8B 4C 24 04        mov         ecx,dword ptr [esp+4]
   00000004: 8B 01              mov         eax,dword ptr [ecx]
   00000006: 83 40 1C 07        add         dword ptr [eax+1Ch],7
   0000000A: 8B 44 24 08        mov         eax,dword ptr [esp+8]
   0000000E: 8B 00              mov         eax,dword ptr [eax]
   00000010: C7 40 0C 0A 00 00  mov         dword ptr [eax+0Ch],0Ah
             00
   00000017: 8B 01              mov         eax,dword ptr [ecx]
   00000019: 83 40 1C 2A        add         dword ptr [eax+1Ch],2Ah
   0000001D: C3                 ret

?test2@@YAXPAH0@Z (void __cdecl test2(int *,int *)):
   00000000: 8B 4C 24 04        mov         ecx,dword ptr [esp+4]
   00000004: 8B 44 24 08        mov         eax,dword ptr [esp+8]
   00000008: 83 41 1C 07        add         dword ptr [ecx+1Ch],7
   0000000C: C7 40 0C 0A 00 00  mov         dword ptr [eax+0Ch],0Ah
             00
   00000013: 83 41 1C 2A        add         dword ptr [ecx+1Ch],2Ah
   00000017: C3                 ret

?test3@@YAXPIAH0@Z (void __cdecl test3(int * __restrict,int * __restrict)):
   00000000: 8B 4C 24 04        mov         ecx,dword ptr [esp+4]
   00000004: 8B 44 24 08        mov         eax,dword ptr [esp+8]
   00000008: 83 41 1C 31        add         dword ptr [ecx+1Ch],31h
   0000000C: C7 40 0C 0A 00 00  mov         dword ptr [eax+0Ch],0Ah
             00
   00000013: C3                 ret

---- GCC 4.7 -----------------------------------------------------
00000160 <test1(std::vector<int, std::allocator<int> >&, 
std::vector<int, std::allocator<int> >&)>:
  160:	8b 44 24 04          	mov    eax,DWORD PTR [esp+0x4]
  164:	8b 54 24 08          	mov    edx,DWORD PTR [esp+0x8]
  168:	8b 00                	mov    eax,DWORD PTR [eax]
  16a:	8b 12                	mov    edx,DWORD PTR [edx]
  16c:	83 40 1c 07          	add    DWORD PTR [eax+0x1c],0x7
  170:	c7 42 0c 0a 00 00 00 	mov    DWORD PTR [edx+0xc],0xa
  177:	83 40 1c 2a          	add    DWORD PTR [eax+0x1c],0x2a
  17b:	c3                   	ret

00000180 <test2(int*, int*)>:
  180:	8b 44 24 04          	mov    eax,DWORD PTR [esp+0x4]
  184:	8b 54 24 08          	mov    edx,DWORD PTR [esp+0x8]
  188:	83 40 1c 07          	add    DWORD PTR [eax+0x1c],0x7
  18c:	c7 42 0c 0a 00 00 00 	mov    DWORD PTR [edx+0xc],0xa
  193:	83 40 1c 2a          	add    DWORD PTR [eax+0x1c],0x2a
  197:	c3                   	ret

000001a0 <test3(int*, int*)>:
  1a0:	8b 44 24 04          	mov    eax,DWORD PTR [esp+0x4]
  1a4:	8b 54 24 08          	mov    edx,DWORD PTR [esp+0x8]
  1a8:	c7 42 0c 0a 00 00 00 	mov    DWORD PTR [edx+0xc],0xa
  1af:	8b 50 1c             	mov    edx,DWORD PTR [eax+0x1c]
  1b2:	83 c2 31             	add    edx,0x31
  1b5:	89 50 1c             	mov    DWORD PTR [eax+0x1c],edx
  1b8:	c3                   	ret
---- End GCC 4.7 -----------------------------------------------

For some more fun:

int test4() {
     int* v1 = (int*) malloc(10*sizeof(int));
     int* v2 = (int*) malloc(10*sizeof(int));
     v1[1] += 0x77;
     v2[2] += 0x42;
     v1[1] -= 0x77;
     return v1[1];
}

int test5() {
     std::vector<int> v1(10);
     std::vector<int> v2(10);
     v1[1] += 0x77;
     v2[2] += 0x42;
     v1[1] -= 0x77;
     return v1[1];
}

template<class T> class simple_vector {
public:
     simple_vector(size_t size) : elems((int*)malloc(size*sizeof(T))), 
size(size), capacity(size) {}
     ~simple_vector() { free(elems); }
     T& operator[](size_t idx) { return elems[idx]; }
private:
     T* elems; size_t size; size_t capacity;
};

int test6() {
     simple_vector<int> v1(10);
     simple_vector<int> v2(10);
     v1[1] += 0x77;
     v2[2] += 0x42;
     v1[1] -= 0x77;
     return v1[1];
}

For test4(), both Visual C++ and GCC can figure out that there is no 
aliasing. For test5() both can't. For test6(), Visual C++ thinks there 
can be aliasing, GCC gets it right. (Disassembly not posted, it's way 
too big.)
0
tni1 (1)
8/31/2012 8:17:46 PM
David Brown <david@westcontrol.removethisbit.com> writes:
> On 30/08/2012 23:07, Keith Thompson wrote:
[...]
>> If I were designing a C-like language from scratch today, I'd
>> separate the concepts of characters and fundamental storage units.
>> I'd probably also separate the concept of very short integers
>> from both.  So `char`, `byte`, and `int8` might be three distinct
>> and incompatible types.
>>
>> Making such a change to C now would break so much code that the
>> resulting language could not reasonably be called "C"; it ain't
>> gonna happen.
>
> This is pretty much exactly what Python did with Python 3.  Previously, 
> strings and characters were also used as raw data - now they are 
> separate types.  But I agree that it is not going to happen in C.
>
> I would be happy with a "byte" being officially defined as the type for 
> memory units, however.  Maybe "data8_t" would be more appropriate - then 
> we could have "data16_t", etc., as well.

The name "data8_t" works only if a byte is 8 bits, something that's
not guaranteed by the language.

If you want to require CHAR_BIT to be exactly 8, there's an argument
to be made for that, though it would exclude some systems (mostly
DSPs (digital signal processors), I think) from having conforming
C implementations.

Otherwise, the size in bits of the fundamental memory unit *has*
to be implementation-defined.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
8/31/2012 8:41:30 PM
On Thursday, August 30, 2012 10:10:32 PM UTC-4, Garrett Hartshaw wrote:
> 
> One of the major uses of typedef is to allow this kind of
> 
> disambiguation between types that are represented identically. While I
> 
> don't often have need to work low-level directly on bytes, if I did I
> 
> would not hesitate to create a byte_t typedef, and if it was already
> 
> included in the standard, so much the better (although I would
> 
> probably typedef it as 'unsigned char' to avoid the
> 
> implementation-defined signed-ness of plain 'char').
> 
> 
> 
> However, even if 'byte_t' were added to the standard, I would still
> 
> want to distinguish between 'byte_t *' (used as a pointer to a byte)
> 
> and 'void *' (used as an opaque pointer or a pointer to uninitialized
> 
> memory) *even if they both meant the same thing to the compiler*.
> 
> 
> 
> Granted it would better for 'memcpy' and friends to use 'byte_t *'
> 
> rather than 'void *', as their underlying functionality is specified
> 
> in terms of moving/copying bytes. 'void *' would still be required *in
> 
> C* as the return value of 'malloc' (unitialized memory) and for use as
> 
> a userData parameter in callbacks (opaque pointer to an object of
> 
> unspecified type). There is little use for 'void *' in pure C++ code,
> 
> but it would still be required in the language to interface with C code.
> 

Currently I have a function like this

int cmw::sockRead (sock_type sock, void* data, int len
                   , sockaddr* fromAddr, socklen_t* fromLen)
{
  int rc = recvfrom(sock
                    , static_cast<char*> (data)
                    , len
                    , 0
                    , fromAddr
                    , fromLen
                   );
 ...
}

I believe the cast is needed on Windows.  To start 
using a byte_t would you suggest

typedef uint8_t byte_t

on Linux and  
typedef int8_t byte_t 
on Windows?

Thanks.

Brian
Ebenezer Enterprises
http://webEbenezer.net
0
woodbrian77 (416)
8/31/2012 11:03:46 PM
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 08/31/2012 07:03 PM, woodbrian77@gmail.com wrote:
> On Thursday, August 30, 2012 10:10:32 PM UTC-4, Garrett Hartshaw
> wrote:
>> 
>> One of the major uses of typedef is to allow this kind of
>> 
>> disambiguation between types that are represented identically.
>> While I
>> 
>> don't often have need to work low-level directly on bytes, if I
>> did I
>> 
>> would not hesitate to create a byte_t typedef, and if it was
>> already
>> 
>> included in the standard, so much the better (although I would
>> 
>> probably typedef it as 'unsigned char' to avoid the
>> 
>> implementation-defined signed-ness of plain 'char').
>> 
>> 
>> 
>> However, even if 'byte_t' were added to the standard, I would
>> still
>> 
>> want to distinguish between 'byte_t *' (used as a pointer to a
>> byte)
>> 
>> and 'void *' (used as an opaque pointer or a pointer to
>> uninitialized
>> 
>> memory) *even if they both meant the same thing to the
>> compiler*.
>> 
>> 
>> 
>> Granted it would better for 'memcpy' and friends to use 'byte_t
>> *'
>> 
>> rather than 'void *', as their underlying functionality is
>> specified
>> 
>> in terms of moving/copying bytes. 'void *' would still be
>> required *in
>> 
>> C* as the return value of 'malloc' (unitialized memory) and for
>> use as
>> 
>> a userData parameter in callbacks (opaque pointer to an object
>> of
>> 
>> unspecified type). There is little use for 'void *' in pure C++
>> code,
>> 
>> but it would still be required in the language to interface with
>> C code.
>> 
> 
> Currently I have a function like this
> 
> int cmw::sockRead (sock_type sock, void* data, int len , sockaddr*
> fromAddr, socklen_t* fromLen) { int rc = recvfrom(sock ,
> static_cast<char*> (data) , len , 0 , fromAddr , fromLen ); ... }
> 
> I believe the cast is needed on Windows.  To start using a byte_t
> would you suggest
> 
> typedef uint8_t byte_t
> 
> on Linux and typedef int8_t byte_t on Windows?
> 
> Thanks.
> 
> Brian Ebenezer Enterprises http://webEbenezer.net
> 

I would use 'typedef uint8_t byte_t' on both platforms (not that it
really matters, but I generally think of a byte as being an unsigned
value) You could also have a 'typedef int8_t sbyte_t' or similar if
you need a value that represents a signed byte.

I would write the function in question as

typedef uint8_t byte_t;
....
int cmw::sockRead( sock_type sock, byte_t * data, int len,
                   sockaddr * fromAddr, socklen_t * fromLen )
{
  int rc = recvfrom( sock, static_cast<char *>( data ), len,
                     0, fromAddr, fromLen );
  ...
}

Looking at the documentation for recvfrom, it appears the cast is
indeed needed in Windows (but not in Linux) as the 'data' parameter is
'char *' in the Windows version and 'void *' in Linux.

I believe that you would still need the cast even if you used the
int8_t typedef, as 'int8_t' == 'signed char' != 'char' (assuming
CHAR_BIT == 8).
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.19 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJQQVTGAAoJEP8JewLaHvzSf6EH/ieh5aBBYZhJIlmZEmKNX+h5
uiloQ6M3ao7NKwCgaEouApqCDCK2zZbReZZFoWavgOJu2sSoxkxxbpHf/gxehyWi
QQJWYtb6XBjNnB7zQIKfn/bP4JFIDC9qg55xm+qYJpVGcG3sOBJr9uEZfm8oonck
kvd+/5uT4Y9sZey6pg7aiw9HvdpVgIBVnx7RqYkDrW/z9Ncjl3mTPOArzzLMsuT/
uEe29TBrHeC0YncENH0pcoIuHJ3dkjEx4LJFN8yyMiPytUquPBcdfO69vaUm0w4b
uSd3xTP5RLmk57Wczid7DtidxxMmOAfYzZQNIVSFOKKOkVrKhgpyEj37pRVLyLA=
=0Dog
-----END PGP SIGNATURE-----
0
ghartshaw (25)
9/1/2012 12:20:22 AM
Kenneth Brody <kenbrody@spamcop.net> writes:
> On 8/30/2012 8:30 PM, Keith Thompson wrote:
>> Jens Gustedt <jens.gustedt@loria.fr> writes:
> [...]
>>> so "void*" says pointer to void. This is not "nothing" or "unknown",
>>> in that sense void is not much different from "struct nix" when you
>>> never actually define "struct nix" somewhere. It behaves a bit
>>> different in terms of implicit conversions, sure, but the sematic is
>>> the same.
>>
>> Not really.  A `char*` pointer points to an object of type `char`.  A
>> `void*` pointer does not point to an object of type `void`, because
>> there is no such thing.
>>
>> Any type of pointer to object or incomplete type (i.e., any pointer
>> other than a function pointer) points to some object in memory (or to
>> nothing if it's currently a null pointer).  What's special about `void*`
>> is that, while you can perform certain pointer operations on it, you
>> can't access the object it points to without first converting it to some
>> other pointer type.
> [...]
>
> While technically correct that "void *" doesn't point to an object of
> type "void" because there's no such thing, I think it is convenient to
> think of it in those terms.

I disagree.  That is, I agree that it's technically correct (the
best kind of correct!), but I think it's correct in every other
sense as well.  I don't think pretending that there's such a thing
as an object of type void, that a void* pointer points to, is useful.

> Consider, for example:
>
>     struct IncompleteType;
>     typedef struct IncompleteType MyVoid;
>
> In this case, "MyVoid *" is kind of like "void *", as long as struct
> IncompleteType is never "completed".

And that's a *huge* difference.  If you have a pointer to struct,
even if the struct type hasn't yet been completed, it tells you
that it actually points to an object of that type.  Presumably code
that has visibility to the full definition of struct IncompleteType
will be able to dereference the pointer and access the pointed-to
object.  And that's the whole point of declaring something as struct
IncompleteType*.

On the other hand, if you deliberately never complete the type
struct IncompleteType, then there can be no objects of type struct
IncompleteType, and you'll never able to dereference a pointer to
struct IncompleteType without first converting it to some other
pointer type.  If void* didn't exist, that might be a reasonable
thing to do -- but it does.

[...]
> As I said, it is technically correct that "void *" cannot point to
> something of type "void", because there is no such thing.  (You can't
> have an object of type "struct IncompleteType" in my example, either.)
> However, I do think it's a convenient way to think of it, since any
> other "X *" would be a pointer to something of type "X".

Yes, any *other* type X* points to something of type X.  void*
is an exception to that rule, which is why it exists.

[...]

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
9/1/2012 12:24:40 AM
Scott Lurndal wrote:
> Jens Gustedt <jens.gustedt@loria.fr> writes:
>> Am 30.08.2012 00:21, schrieb Casey Carter:
>>> On 2012-08-29 16:23, Jens Gustedt wrote:
>>>> 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 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
>>
>
> What about the existing massive volumes of C++ code which use void*?  Particularly
> code that dates from the 80's when there was no STL?
>


So use the old compiler. Check *everything* in to the CM system; ideally
you can run a script that'll check it out, install the tools  and build 
it all in one fell swoop. Makes for a fine test of the CM system....

--
Les Cargill
0
lcargill991 (563)
9/1/2012 2:10:02 AM
On Friday, August 31, 2012 8:23:38 PM UTC-4, Garrett Hartshaw wrote:
> 
> 
> I would use 'typedef uint8_t byte_t' on both platforms (not that it
> 
> really matters, but I generally think of a byte as being an unsigned
> 
> value) You could also have a 'typedef int8_t sbyte_t' or similar if
> 
> you need a value that represents a signed byte.
> 
> 
> 
> I would write the function in question as
> 
> 
> 
> typedef uint8_t byte_t;
> 
> ...
> 
> int cmw::sockRead( sock_type sock, byte_t * data, int len,
> 
>                    sockaddr * fromAddr, socklen_t * fromLen )
> 
> {
> 
>   int rc = recvfrom( sock, static_cast<char *>( data ), len,
> 
>                      0, fromAddr, fromLen );
> 
>   ...
> 
> }
> 

I tried that and the compiler didn't accept the cast.
I think it would have to be a reinterpret_cast.


> 
> 
> Looking at the documentation for recvfrom, it appears the cast is
> 
> indeed needed in Windows (but not in Linux) as the 'data' parameter is
> 
> 'char *' in the Windows version and 'void *' in Linux.
> 
> 
> 
> I believe that you would still need the cast even if you used the
> 
> int8_t typedef, as 'int8_t' == 'signed char' != 'char' (assuming
> 
> CHAR_BIT == 8).
> 

OK. I am checking that CHAR_BIT == 8.  


Brian
Ebenezer Enterprises
http://webEbenezer.net
0
woodbrian77 (416)
9/1/2012 2:57:46 AM
; Wrote: 
> 
<br><strong><a
href="http://www.booksunglasses.com/oakley-sunglasses-c-108.html">Oakley
Sunglasses</a></strong><br><strong><a
href="http://www.booksunglasses.com/oakley-sunglasses-c-108.html">Oakley
Sunglasses Sale</a></strong><strong><a
href="http://www.booksunglasses.com/oakley-sunglasses-c-108.html">Discount
Oakley Sunglasses</a></strong><strong><a
href="http://www.booksunglasses.com/oakley-sunglasses-c-108.html">Cheap
Oakley Sunglasses</a></strong><strong><a
href="http://www.booksunglasses.com/oakley-sunglasses-c-108.html">Oakley
Sunglasses Online</a></strong><br>


-- 
wenbowcarm
------------------------------------------------------------------------
wenbowcarm's Profile: http://forums.yourdomain.com.au/member.php?userid=785
View this thread: http://forums.yourdomain.com.au/showthread.php?t=5300

0
9/1/2012 1:33:40 PM
tni skrev 2012-08-31 22:17:
> On 2012-08-29 21:33, Bo Persson wrote:
>> David Brown wrote 2012-08-29 09:51:
>>
>>> But it will be a long time before compiler technology can figure out all
>>> cases of "restrict" by itself - that requires insight between different
>>> compile units, and hefty analysis on the way the functions are used.
>>>
>>
>> The argument from the C++ camp, for not implementing it, is that it is a
>> lot less useful in C++. Most functions don't take pointers to basic
>> types as parameters, because C++ is largely class based.
>>
>> Type based alias analysis will show that function parameters cannot
>> alias, because they are of different class types. Adding restrict will
>> not help.
>>
>> If you have
>>
>> void f(std::vector<int>& v1, std::vector<int>& v2)
>> {
>>     // Here v1[1] can never, ever alias v2[2]
>>     // because vectors don't work that way, and the compiler can tell
>> }
>>
>> on the other hand, with C style code
>>
>> void f(int* v1, int* v2)
>> {
>>     // Here any v1[i] might alias any v2[j]
>>     // because the function just COULD have been called
>>     // with f(p, p + 7)
>>
>> }
>
> Of course, you are dead wrong. The two vectors can potentially alias
> (the compiler will have a really hard time proving otherwise, it would
> have to be able to track the underlying storage over the entire
> lifetime; neither Visual C++ nor GCC get it right, even in trivial cases).
>
[...]

Yes, the same index in two vectors can alias. Different index cannot.

With an array, every element can potentially alias any element in the 
other array.

Big difference!


Bo Persson


0
bop (1086)
9/1/2012 1:39:28 PM
On Aug 31, 3:29=A0pm, sc...@slp53.sl.home (Scott Lurndal) wrote:
> Nick Keighley <nick_keighley_nos...@hotmail.com> writes:
> >On Aug 30, 9:17=3DA0am, Jens Gustedt <jens.gust...@loria.fr> wrote:
>
> >> You just should push the button a bit further where Leigh stopped. He
> >> resolved the term "void" but didn't for "char". "char" is the smallest
> >> addressable unit in C and C++ (Pascal had byte for that, no)
>
> >no. Pascal did not have a byte type
>
> Well, perhaps not in the "standard", but it was a common extension:
>
> e.g. VAX Pascal:
>
> [INHERIT('SYS$SHARE:STARLET'),
> =A0IDENT('V03-001')]
>
> PROGRAM Users( OUTPUT );
>
> TYPE
> =A0 Unsigned_byte =3D [BYTE] 0..255;
> =A0 Signed_word =A0 =3D [WORD] -32768..+32767;
> =A0 Unsigned_word =3D [WORD] 0..65535;
>
> =A0 jpi$item =A0 =A0 =A0=3D [BYTE(12)] PACKED RECORD
> =A0 =A0 =A0 =A0 Buffer_length: =A0[POS(0)] Unsigned_word;
> =A0 =A0 =A0 =A0 Item_code: =A0 =A0 =A0[POS(16)] Unsigned_word;
> =A0 =A0 =A0 =A0 Buffer_address: [POS(32),LONG,UNSAFE] UNSIGNED;
> =A0 =A0 =A0 =A0 Buflen_address: [POS(64),LONG,UNSAFE] UNSIGNED;
> =A0 END;
>
> =A0 Terminfo_rec =A0=3D [BYTE(80)] RECORD
> =A0 =A0 =A0 =A0 Csp_id: =A0 =A0 =A0 =A0 [BYTE(04),POS(0),KEY(0)] PACKED A=
RRAY [1..04] OF CHAR;
> =A0 =A0 =A0 =A0 Junk: =A0 =A0 =A0 =A0 =A0 [BYTE(27)] PACKED ARRAY [1..27]=
 OF CHAR;
> =A0 =A0 =A0 =A0 Short: =A0 =A0 =A0 =A0 =A0[BYTE(09)] PACKED ARRAY [1..09]=
 OF CHAR;
> =A0 =A0 =A0 =A0 Long: =A0 =A0 =A0 =A0 =A0 [BYTE(21)] PACKED ARRAY [1..21]=
 OF CHAR;
> =A0 =A0 =A0 =A0 Csp_long: =A0 =A0 =A0 [BYTE(07)] PACKED ARRAY [1..07] OF =
CHAR;
> =A0 =A0 =A0 =A0 Filler: =A0 =A0 =A0 =A0 [BYTE(12)] PACKED ARRAY [1..12] O=
F CHAR;
> =A0 END;
>
> =A0 Csp_stat_rec =A0=3D [LONG] PACKED RECORD
> =A0 =A0 =A0 =A0 Ss_status: =A0 =A0 =A0[POS(00)] Unsigned_word;
> =A0 =A0 =A0 =A0 Port: =A0 =A0 =A0 =A0 =A0 [POS(16)] Unsigned_byte;
> =A0 =A0 =A0 =A0 Machine: =A0 =A0 =A0 =A0[POS(24)] Unsigned_byte;
> =A0 END;

good grief. *Thats* Pascal! Looks more like CORAL-66
0
9/1/2012 1:45:45 PM
"David Brown" <david@westcontrol.removethisbit.com> ha scritto nel messaggio
news:P5GdnWFfH-QqHt3NnZ2dnUVZ7vudnZ2d@lyse.net...
> The active part of the language is for talking to the compiler /and/ humans.
> That is the reason we have typedefs, and the reason we give variables useful
> names rather than "i1", "i2", etc.
>
>> If the differences, for the
>> compiler, between 'void*' and 'char*' were reduced to a matter of how
>> they were spelled, I would not recommend using that spelling to convey
>> meaningful information to any humans who were reading the code.
>
> If you don't think "void*" and "char*" convey a different meaning to humans,
> then I see your point.  IMHO, they /do/ convey a different meaning - so they
> have different usage even if they had identical functional meaning.

"void*"  add only complexity to the language...
the same "const" keyword

the people propose this type are wrong...
because make complex what is already simple...

all can be done using unsigned char* or better uint8_t*  etc
as a general pointer to data

Buon Giorno


0
io_x
9/1/2012 5:02:54 PM
On Sunday, August 26, 2012 4:57:30 AM UTC-5, Ansel wrote:
> Isn't it a lame use of human time and effort to maintain completely separate 
> C and C++ standards? 

Isn't is a lame use of human time and effort to have, what, 
eleventy million different programming languages in the first place?  
Why stop with C and C++?  Why not roll in Java and C# and Objective-C?  

C and C++ are different languages with a large common subset.  
Why is that a problem?  
0
jfbode1029 (228)
9/1/2012 5:35:09 PM
=D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=A9=D7=91=D7=AA,=
 1 =D7=91=D7=A1=D7=A4=D7=98=D7=9E=D7=91=D7=A8 2012 18:35:09 UTC+1, =D7=9E=
=D7=90=D7=AA John Bode:
> On Sunday, August 26, 2012 4:57:30 AM UTC-5, Ansel wrote:
>=20
> Isn't is a lame use of human time and effort to have, what, =20
> eleventy million different programming languages in the first place? =20
>=20
> Why stop with C and C++?  Why not roll in Java and C# and Objective-C? =
=20
>=20
Yes, we badly need one programming language that does everything. Twenty di=
fferent ways of writing a for loop is unacceptable.
0
9/1/2012 7:47:15 PM
On 2012-08-26, Ansel <tinker454@trytospammenowloser.com> wrote:
> Isn't it a lame use of human time and effort to maintain completely separate 
> C and C++ standards?

Maintaining these standards is just the hobby of some people who have
been put out to pasture.

Who cares if they are wasting /their/ time; the problem is that, while they
may improve a little thing here and there, they are wrecking the languages
(because some fools in the world actually take them seriously).

I do not use any syntax or function* newer than the 1995 C technical corrigendum
(which added some badly needed wchar_t related functionality to the nearly
perfect C90 language).

In C++ programming, I stick to 1998 C++, which mostly got it right.

Just say no to these clowns.

Language standardization should be about one thing and one thing only:
surveying the existing practice (what is implemented), identifying what is
common and codifying it (perhaps with some small adjustments to bring
nearly equivalent features together).

The situation where you have a new standard, most of which is not implemented
anywhere, is completely ridiculous and wrong.

--
* By function I mean standard C function, not platform-specific API function,
of course!
0
kaz15 (1143)
9/1/2012 10:45:13 PM
On 01/09/2012 23:45, Kaz Kylheku wrote:
> On 2012-08-26, Ansel <tinker454@trytospammenowloser.com> wrote:
>> Isn't it a lame use of human time and effort to maintain completely separate
>> C and C++ standards?
>
> Maintaining these standards is just the hobby of some people who have
> been put out to pasture.
>
> Who cares if they are wasting /their/ time; the problem is that, while they
> may improve a little thing here and there, they are wrecking the languages
> (because some fools in the world actually take them seriously).
>
> I do not use any syntax or function* newer than the 1995 C technical corrigendum
> (which added some badly needed wchar_t related functionality to the nearly
> perfect C90 language).
>
> In C++ programming, I stick to 1998 C++, which mostly got it right.
>
> Just say no to these clowns.
>
> Language standardization should be about one thing and one thing only:
> surveying the existing practice (what is implemented), identifying what is
> common and codifying it (perhaps with some small adjustments to bring
> nearly equivalent features together).
>
> The situation where you have a new standard, most of which is not implemented
> anywhere, is completely ridiculous and wrong.

You are an idiot.

/Leigh

0
leigh (1128)
9/2/2012 12:07:30 AM
On Fri, 31 Aug 2012 17:24:40 -0700, Keith Thompson wrote:

>> Consider, for example:
>>
>>     struct IncompleteType;
>>     typedef struct IncompleteType MyVoid;
>>
>> In this case, "MyVoid *" is kind of like "void *", as long as struct
>> IncompleteType is never "completed".
> 
> And that's a *huge* difference.  If you have a pointer to struct,
> even if the struct type hasn't yet been completed, it tells you
> that it actually points to an object of that type.  Presumably code
> that has visibility to the full definition of struct IncompleteType
> will be able to dereference the pointer and access the pointed-to
> object.  And that's the whole point of declaring something as struct
> IncompleteType*.

Also: alignment. An implementation can impose a minimum alignment for 
structures (even incomplete structures). The representation of MyVoid*
only has to allow for such alignment, meaning that (unlike void*) it may
not be possible to reliably convert a char* to a MyVoid* then back to a
char* (on a word-aligned architecture, a MyVoid* only needs enough bits
for the word address, whearas a void* must have enough bits for the offset
within a word if char is smaller than a word).

0
nobody (5159)
9/2/2012 12:10:06 AM
John Bode wrote:
> On Sunday, August 26, 2012 4:57:30 AM UTC-5, Ansel wrote:
>> Isn't it a lame use of human time and effort to maintain completely
>> separate C and C++ standards?
>
> Isn't is a lame use of human time and effort to have, what,
> eleventy million different programming languages in the first place?

Well, yes, of course.  But C/C++ers are like addicts and need much more 
transition time and some will just never make it without their vice. So 
then, a common ground for C/C++ is like step 1 of the 12-step-method for 
them.

> Why stop with C and C++?

Shhhh. That is not the plan.

>  Why not roll in Java and C# and Objective-C?

Many are trying that, but just like hope that a president or government can 
rescue humanity is, of course, ludacrous. (BTW, after the republicans' 
convention, it sure does look like Obama is a shoe-in for another 4 years, 
huh.)

> C and C++ are different languages with a large common subset.
> Why is that a problem?

It's not common ENOUGH. Mostly, the C++ programmers will have to help the C 
programmers adapt to a future that some of them will still see, lest they 
become the next wave of homeless when the <you know whos> kick them to the 
curb. Making C/C++ more like one thing is like throwing a lifesaver to the 
drowning C programmers. 


0
blankone23 (22)
9/2/2012 4:06:14 AM
Malcolm McLean wrote:
> ?????? ??? ???, 1 ??????? 2012 18:35:09 UTC+1, ??? John Bode:
>> On Sunday, August 26, 2012 4:57:30 AM UTC-5, Ansel wrote:
>>
>> Isn't is a lame use of human time and effort to have, what,
>> eleventy million different programming languages in the first place?
>>
>> Why stop with C and C++?  Why not roll in Java and C# and
>> Objective-C?
>>
> Yes, we badly need one programming language that does everything.
> Twenty different ways of writing a for loop is unacceptable.

"Put your money where your mouth is!". IOW, talk is cheap. Are you asking 
for something, or suggesting you know what to do? 


0
blankone23 (22)
9/2/2012 4:07:37 AM
Kaz Kylheku wrote:
> On 2012-08-26, Ansel <tinker454@trytospammenowloser.com> wrote:
>> Isn't it a lame use of human time and effort to maintain completely
>> separate C and C++ standards?
>
> Maintaining these standards is just the hobby of some people who have
> been put out to pasture.

Which is all fine and dandy, until it negatively affects others. Like, e.g., 
the newbs who the olds are keen to impress on. IOW, smoking yourself to 
death is totally up to you. Start pushing your bad habits on others, then 
it's a problem.

>
> Who cares if they are wasting /their/ time;

I actually do if that is not the situation they really want to be in.

> the problem is that,
> while they
> may improve a little thing here and there, they are wrecking the
> languages (because some fools in the world actually take them
> seriously).

That's kinda what I said above.

>
> I do not use any syntax or function* newer than the 1995 C technical
> corrigendum (which added some badly needed wchar_t related
> functionality to the nearly perfect C90 language).
>
> In C++ programming, I stick to 1998 C++, which mostly got it right.

The only way to use C/C++ with an eye toward the future is with a healthy 
dose of macros, and the built-in preprocessors are pretty much not up to the 
task. Perhaps they are crippled on purpose.

>
> Just say no to these clowns.

Most are actually pretty darned smart. But when they start on their "spiel", 
I give it right back to them and then some, but they do not seem to be 
learning from it. I think they see everything as a pissing contest. Have you 
ever seen a C or C++ programmer admit that they were wrong or that someone 
else actually has a good point? They see everything as a threat. I guess 
that is what a focus on sports in schools and fraterneties result in. Sigh. 
I think this is why much of the world sees "Americans" as stupid. Which, of 
course, begs the question, "Is USA's largest export, stupidity?".

>
> Language standardization should be about one thing and one thing only:
> surveying the existing practice (what is implemented), identifying
> what is common and codifying it (perhaps with some small adjustments
> to bring
> nearly equivalent features together).

See, now I've heard that over the years, many times. I still don't think it 
is true. But I'm not sure it should be that either, but maybe. If someone 
starts a new thread on this, I promise to read all posts in it. You have a 
fine example in progress on this: Jacob Navia and his "CCL": he is scheduled 
to pitch it next month (wow, last month already, I thought it was THIS 
month, but it is actually NEXT month!) but the "it" he is going to pitch is 
NOT "standard practice", but rather some kind of "request to develop or 
solicit proposals" or something, which goes entirely against the "codify 
existing practice" mantra. Can you make heads or tails out of this?

>
> The situation where you have a new standard, most of which is not
> implemented anywhere, is completely ridiculous and wrong.

I've suggested that maybe the ISO standard process for C/C++ is broken, but 
it's probably more than that: byzantine failure. 


0
blankone23 (22)
9/2/2012 4:29:09 AM
Leigh Johnston wrote:
> On 01/09/2012 23:45, Kaz Kylheku wrote:
>> On 2012-08-26, Ansel <tinker454@trytospammenowloser.com> wrote:
>>
>> The situation where you have a new standard, most of which is not
>> implemented anywhere, is completely ridiculous and wrong.
>
> You are an idiot.
>

WTF? Just because "you can't handle the truth!", I'm fired and some 
unqualified fool is to replace me?! Is this a trick? I'm NOT going to beg to 
keep "my job", nor will I take a pay cut. (I'm gonna cost you twice as much 
as a consultant, you know... umm, nevermind! HIRE the FOOL! :-) ). 


0
blankone23 (22)
9/2/2012 4:34:28 AM
Op 28-Aug-12 23:12, Melzzzzz schreef:
> On Tue, 28 Aug 2012 23:00:16 +0200
> Jens Gustedt <jens.gustedt@loria.fr> wrote:
>
>>
>> I'd still like to hear of a plausible use case for "void*" in C++ that
>> is not related to C compability or to the overloading of "operator
>> new".
>>
> Well, when implementing template container for pointers, it is great
> optimization to use just single class specialized for pointers to void,
> and cast to appropriate pointer type in specialized classes,
> while using single implementation.
> It greatly reduces code size.

It *may* greatly reduce code size, if the compiler doesn't do this 
optimization (sharing implementation of pointer templates) already for you.

0
dombo (246)
9/2/2012 8:56:18 PM
Op 31-Aug-12 0:18, Jens Gustedt schreef:
> Am 30.08.2012 19:49, schrieb Garrett Hartshaw:

>> If on the other hand you wish to have an opaque pointer to an object
>> of unknown type, or to an uninitialized memory region, then use 'void *'.
>
> A "void*" pointer is not "an uninitialized" memory region. It may well
> already be initialized.
>
> But I am really surprised about this strong need of opaque pointer in
> C++. If we follow the basic ideas of C++ such a usage should be very
> rare in C++, no? Isn't that what "abstract base classes" have been
> invented for?

I've been programming C++ for almost 20 years now, I don't remember 
having ever having a need to use void* other than to interface with C 
code (typically when registering a callback on a C API, where context 
information can be passed back to the callback function via a void*).

0
dombo (246)
9/2/2012 9:14:18 PM
On 2012-09-02, Leigh Johnston <leigh@i42.co.uk> wrote:
> You are an idiot.

Yes, and to prove it I'm starting an insoluble ISO committee dedicated
to buggering Up a perfectly good programming language.

I won't go so far as to quote an entire article just to add one line,
though.
0
kaz15 (1143)
9/2/2012 9:35:40 PM
; Wrote: 
> 
<br><strong><a
href="http://www.dresshave.com/bridesmaid-dresses-c-45.html">Bridesmaid
Dresses</a></strong><strong><a
href="http://www.dresshave.com/bridesmaid-dresses-c-45.html">Bridesmaid
Gowns</a></strong><strong><a
href="http://www.dresshave.com/bridesmaid-dresses-c-45.html">Discount
Bridesmaid Dresses</a></strong><strong><a
href="http://www.dresshave.com/bridesmaid-dresses-c-45.html">Cheap
Bridesmaid Dresses</a></strong><br><strong><a
href="http://www.dresshave.com/bridesmaid-dresses-c-45.html">Bridesmaid
Dress
Sale</a></strong><br>ÎïÒµ6Ôª£¬300ƽ·½£¬2Ôª.µç»°18616850982


-- 
tesnutquin
------------------------------------------------------------------------
tesnutquin's Profile: http://forums.yourdomain.com.au/member.php?userid=781
View this thread: http://forums.yourdomain.com.au/showthread.php?t=5300

0
9/2/2012 11:56:17 PM
On 01/09/2012 15:39, Bo Persson wrote:
> tni skrev 2012-08-31 22:17:
>> On 2012-08-29 21:33, Bo Persson wrote:
>>> David Brown wrote 2012-08-29 09:51:
>>>
>>>> But it will be a long time before compiler technology can figure out
>>>> all
>>>> cases of "restrict" by itself - that requires insight between different
>>>> compile units, and hefty analysis on the way the functions are used.
>>>>
>>>
>>> The argument from the C++ camp, for not implementing it, is that it is a
>>> lot less useful in C++. Most functions don't take pointers to basic
>>> types as parameters, because C++ is largely class based.
>>>
>>> Type based alias analysis will show that function parameters cannot
>>> alias, because they are of different class types. Adding restrict will
>>> not help.
>>>
>>> If you have
>>>
>>> void f(std::vector<int>& v1, std::vector<int>& v2)
>>> {
>>>     // Here v1[1] can never, ever alias v2[2]
>>>     // because vectors don't work that way, and the compiler can tell
>>> }
>>>
>>> on the other hand, with C style code
>>>
>>> void f(int* v1, int* v2)
>>> {
>>>     // Here any v1[i] might alias any v2[j]
>>>     // because the function just COULD have been called
>>>     // with f(p, p + 7)
>>>
>>> }
>>
>> Of course, you are dead wrong. The two vectors can potentially alias
>> (the compiler will have a really hard time proving otherwise, it would
>> have to be able to track the underlying storage over the entire
>> lifetime; neither Visual C++ nor GCC get it right, even in trivial
>> cases).
>>
> [...]
>
> Yes, the same index in two vectors can alias. Different index cannot.
>

That doesn't make sense.  Are you saying that for two vectors v1 and v2, 
v1[10] and v2[10] can alias but v1[10] and v2[11] cannot?

> With an array, every element can potentially alias any element in the
> other array.
>

That's correct - unless you tell the compiler otherwise with "restrict", 
or the compiler can figure it out itself (which is a hard job, and only 
possible in some cases).

If you "open up" a C++ vector implementation, you will see it is 
implemented using pointers and/or "C" arrays - that's the low-level 
tools available to a C++ class library.  It is therefore obvious that no 
C++ class can be smarter about aliasing than the underlying C features.

> Big difference!

Yes, there's a big difference - with a simple class or plain arrays, the 
compiler has a chance of figuring out aliasing correctly.  With C and 
"restrict", you can give the compiler a help.  But with C++ and standard 
vector classes, the compiler must generate the most pessimistic code.

>
>
> Bo Persson
>
>

0
david2384 (2168)
9/3/2012 8:21:40 AM
On 31/08/2012 22:41, Keith Thompson wrote:
> David Brown <david@westcontrol.removethisbit.com> writes:
>> On 30/08/2012 23:07, Keith Thompson wrote:
> [...]
>>> If I were designing a C-like language from scratch today, I'd
>>> separate the concepts of characters and fundamental storage units.
>>> I'd probably also separate the concept of very short integers
>>> from both.  So `char`, `byte`, and `int8` might be three distinct
>>> and incompatible types.
>>>
>>> Making such a change to C now would break so much code that the
>>> resulting language could not reasonably be called "C"; it ain't
>>> gonna happen.
>>
>> This is pretty much exactly what Python did with Python 3.  Previously,
>> strings and characters were also used as raw data - now they are
>> separate types.  But I agree that it is not going to happen in C.
>>
>> I would be happy with a "byte" being officially defined as the type for
>> memory units, however.  Maybe "data8_t" would be more appropriate - then
>> we could have "data16_t", etc., as well.
>
> The name "data8_t" works only if a byte is 8 bits, something that's
> not guaranteed by the language.
>
> If you want to require CHAR_BIT to be exactly 8, there's an argument
> to be made for that, though it would exclude some systems (mostly
> DSPs (digital signal processors), I think) from having conforming
> C implementations.

That's correct.  If we exclude a few dinosaur machines (and I hope we 
can!), almost all current targets have 8-bit "bytes".  The exceptions 
that I know of are, as you say, DSP architectures with either 16-bit or 
even 32-bit minimum access sizes.  It would also be quite simple to use 
9-bit (or multiples thereof) in soft processors in FPGAs, since memory 
banks there are normally 9-bit wide.

I would suggest having these "data?_t" types work in the same way as 
int?_t types today - they are implemented if and only if the target 
supports them.  On a DSP you might then have a data16_t but no data8_t.

Of course, that means that if you write your code using data8_t, it will 
not be portable to a DSP.  But this is a *good* thing, not a problem. 
When moving the code to the DSP, the compiler will complain, and you 
have to change the code to use data16_t (or even data32_t).  This is 
much better than the current situation, where the "portable" code will 
use "unsigned char", it will compile fine on the DSP, and it will almost 
certainly fail to work as expected.

>
> Otherwise, the size in bits of the fundamental memory unit *has*
> to be implementation-defined.
>

0
david2384 (2168)
9/3/2012 8:28:16 AM
On 03.09.2012 10:21, David Brown wrote:
> On 01/09/2012 15:39, Bo Persson wrote:
>> tni skrev 2012-08-31 22:17:
>>> On 2012-08-29 21:33, Bo Persson wrote:
>>>> David Brown wrote 2012-08-29 09:51:
>>>>
>>>>> But it will be a long time before compiler technology can figure out
>>>>> all
>>>>> cases of "restrict" by itself - that requires insight between
>>>>> different
>>>>> compile units, and hefty analysis on the way the functions are used.
>>>>>
>>>>
>>>> The argument from the C++ camp, for not implementing it, is that it
>>>> is a
>>>> lot less useful in C++. Most functions don't take pointers to basic
>>>> types as parameters, because C++ is largely class based.
>>>>
>>>> Type based alias analysis will show that function parameters cannot
>>>> alias, because they are of different class types. Adding restrict will
>>>> not help.
>>>>
>>>> If you have
>>>>
>>>> void f(std::vector<int>& v1, std::vector<int>& v2)
>>>> {
>>>>     // Here v1[1] can never, ever alias v2[2]
>>>>     // because vectors don't work that way, and the compiler can tell
>>>> }
>>>>
>>>> on the other hand, with C style code
>>>>
>>>> void f(int* v1, int* v2)
>>>> {
>>>>     // Here any v1[i] might alias any v2[j]
>>>>     // because the function just COULD have been called
>>>>     // with f(p, p + 7)
>>>>
>>>> }
>>>
>>> Of course, you are dead wrong. The two vectors can potentially alias
>>> (the compiler will have a really hard time proving otherwise, it would
>>> have to be able to track the underlying storage over the entire
>>> lifetime; neither Visual C++ nor GCC get it right, even in trivial
>>> cases).
>>>
>> [...]
>>
>> Yes, the same index in two vectors can alias. Different index cannot.
>>
>
> That doesn't make sense.

That's at best an unthinking remark.


>  Are you saying that for two vectors v1 and v2,
> v1[10] and v2[10] can alias but v1[10] and v2[11] cannot?

Yes, that's what he's saying, and that's correct.


>> With an array, every element can potentially alias any element in the
>> other array.
>>
>
> That's correct - unless you tell the compiler otherwise with "restrict",
> or the compiler can figure it out itself (which is a hard job, and only
> possible in some cases).

Not exactly. He meant "pointer to array as formal argument".


> If you "open up" a C++ vector implementation, you will see it is
> implemented using pointers and/or "C" arrays - that's the low-level
> tools available to a C++ class library.  It is therefore obvious that no
> C++ class can be smarter about aliasing than the underlying C features.

That doesn't follow.


>> Big difference!
>
> Yes, there's a big difference - with a simple class or plain arrays, the
> compiler has a chance of figuring out aliasing correctly.  With C and
> "restrict", you can give the compiler a help.  But with C++ and standard
> vector classes, the compiler must generate the most pessimistic code.

Seems like you forgot your head somewhere today?

Anyway, this is the most eerily absurd article I've read in a long time.

And I've been here a long time.


Cheers & hth.,

- Alf

0
usenet30 (890)
9/3/2012 11:30:49 AM
On 9/3/12 4:21 AM, David Brown wrote:
> On 01/09/2012 15:39, Bo Persson wrote:
>>
>> Yes, the same index in two vectors can alias. Different index cannot.
>>
> 
> That doesn't make sense.  Are you saying that for two vectors v1 and v2,
> v1[10] and v2[10] can alias but v1[10] and v2[11] cannot?
> 

v1 and v2 can be references to the same vector, and thus their
corresponding elements alias. Since a vector has exclusive use of its
"array" member storing its content, and has no operations that can yield
a "sub vector" that references a partial section of the vector, there is
no way for v1[10] and v2[11] to point to the same item.

This is opposed to a built in array (passed via pointers) where v1 could
have been set to &v2[1] and thus v1[10] and v2[11] alias.

>> With an array, every element can potentially alias any element in the
>> other array.
>>
> 
> That's correct - unless you tell the compiler otherwise with "restrict",
> or the compiler can figure it out itself (which is a hard job, and only
> possible in some cases).
> 
> If you "open up" a C++ vector implementation, you will see it is
> implemented using pointers and/or "C" arrays - that's the low-level
> tools available to a C++ class library.  It is therefore obvious that no
> C++ class can be smarter about aliasing than the underlying C features.
> 
>> Big difference!
> 
> Yes, there's a big difference - with a simple class or plain arrays, the
> compiler has a chance of figuring out aliasing correctly.  With C and
> "restrict", you can give the compiler a help.  But with C++ and standard
> vector classes, the compiler must generate the most pessimistic code.
> 

Yes, as far as I know, unless the implementation keys off of special
built in knowledge of std::vector, it can not know that v1[10] and
v2[11] can not alias. In fact, the restrict keyword doesn't help here
(to my understanding). A function being passed raw arrays has the
ability to indicate with restrict that a parameter being passed must not
alias with anything else the function deals with, and thus is able to
optimize things. When passing a vector, you could mark with restrict (if
it was allowed) the pointer/reference parameter you are passing the
vector with to indicate that the function won't see the vector by some
other name, but there is current nothing in C or C++ (that I know of) to
indicate to the compiler that the pointer within vector to its data
array does not alias to any other vectors data array pointer. And vector
can NOT claim that no other pointers into that data array exist, as
iterators for that vector, as well as the results of at or [] will
create such pointers.

0
9/3/2012 5:43:20 PM
On 03/09/2012 19:43, Richard Damon wrote:
> On 9/3/12 4:21 AM, David Brown wrote:
>> On 01/09/2012 15:39, Bo Persson wrote:
>>>
>>> Yes, the same index in two vectors can alias. Different index cannot.
>>>
>>
>> That doesn't make sense.  Are you saying that for two vectors v1 and v2,
>> v1[10] and v2[10] can alias but v1[10] and v2[11] cannot?
>>
>
> v1 and v2 can be references to the same vector, and thus their
> corresponding elements alias. Since a vector has exclusive use of its
> "array" member storing its content, and has no operations that can yield
> a "sub vector" that references a partial section of the vector, there is
> no way for v1[10] and v2[11] to point to the same item.
>
> This is opposed to a built in array (passed via pointers) where v1 could
> have been set to &v2[1] and thus v1[10] and v2[11] alias.
>

OK, I see that point now.

However, while you (and now I) can understand that, I can't see any way 
for the /compiler/ to know and take advantage of that.  There is no way 
to tell the compiler that v1[10] and v2[11] are in different places.  If 
these arrays are statically allocated, the compiler can probably figure 
it out - but for independent dynamically allocated arrays, the compiler 
will have to assume the worst and treat them as may-alias data.

>>> With an array, every element can potentially alias any element in the
>>> other array.
>>>
>>
>> That's correct - unless you tell the compiler otherwise with "restrict",
>> or the compiler can figure it out itself (which is a hard job, and only
>> possible in some cases).
>>
>> If you "open up" a C++ vector implementation, you will see it is
>> implemented using pointers and/or "C" arrays - that's the low-level
>> tools available to a C++ class library.  It is therefore obvious that no
>> C++ class can be smarter about aliasing than the underlying C features.
>>
>>> Big difference!
>>
>> Yes, there's a big difference - with a simple class or plain arrays, the
>> compiler has a chance of figuring out aliasing correctly.  With C and
>> "restrict", you can give the compiler a help.  But with C++ and standard
>> vector classes, the compiler must generate the most pessimistic code.
>>
>
> Yes, as far as I know, unless the implementation keys off of special
> built in knowledge of std::vector, it can not know that v1[10] and
> v2[11] can not alias. In fact, the restrict keyword doesn't help here
> (to my understanding).

I agree here that "restrict" will not be much use.  It could be for some 
cases, such as for vector class methods that worked with two vectors 
(you might have short-cut treatment when the two vectors were the same, 
otherwise make "restrict" copies of the pointers to the data).  But in 
general, you would want the "restrict" to apply to the pointer to the 
data, not to pointers to vectors, and a user of the vector class does 
not have access to that data pointer.

> A function being passed raw arrays has the
> ability to indicate with restrict that a parameter being passed must not
> alias with anything else the function deals with, and thus is able to
> optimize things. When passing a vector, you could mark with restrict (if
> it was allowed) the pointer/reference parameter you are passing the
> vector with to indicate that the function won't see the vector by some
> other name, but there is current nothing in C or C++ (that I know of) to
> indicate to the compiler that the pointer within vector to its data
> array does not alias to any other vectors data array pointer. And vector
> can NOT claim that no other pointers into that data array exist, as
> iterators for that vector, as well as the results of at or [] will
> create such pointers.
>

Yes.

I suppose the conclusion here is that there is not so much use for 
"restrict" in C++ because if you use vectors, you haven't a chance of 
making code as efficient as with C arrays even if you /had/ a "restrict" 
keyword.

(Just to keep the record straight, I know there are other advantages in 
using vectors rather than arrays, and that squeezing out the last drops 
of speed at run-time is not always the most important factor in 
development.)

But from /my/ viewpoint, I want to use C arrays /or/ C++ vectors in C++ 
code, and I want by C array code to be as efficient regardless of 
whether it is compiled as C or C++.  And that means I would like 
"restrict" in C++.

0
david2384 (2168)
9/4/2012 10:47:09 AM
On 04.09.2012 12:47, David Brown wrote:
> On 03/09/2012 19:43, Richard Damon wrote:
>> On 9/3/12 4:21 AM, David Brown wrote:
>>> On 01/09/2012 15:39, Bo Persson wrote:
>>>>
>>>> Yes, the same index in two vectors can alias. Different index cannot.
>>>>
>>>
>>> That doesn't make sense.  Are you saying that for two vectors v1 and v2,
>>> v1[10] and v2[10] can alias but v1[10] and v2[11] cannot?
>>>
>>
>> v1 and v2 can be references to the same vector, and thus their
>> corresponding elements alias. Since a vector has exclusive use of its
>> "array" member storing its content, and has no operations that can yield
>> a "sub vector" that references a partial section of the vector, there is
>> no way for v1[10] and v2[11] to point to the same item.
>>
>> This is opposed to a built in array (passed via pointers) where v1 could
>> have been set to &v2[1] and thus v1[10] and v2[11] alias.
>>
>
> OK, I see that point now.
>
> However, while you (and now I) can understand that, I can't see any way
> for the /compiler/ to know and take advantage of that.  There is no way
> to tell the compiler that v1[10] and v2[11] are in different places.

One way that the compiler is informed, is via the C++ standard.

Which as opposed to the C standard, specifies a lot of higher level 
types in detail.

However, even in C some higher level issues that are specified by the 
standard and cannot easily or at all be inferred from the code itself, 
such as correspondence between fprintf format strings and arguments, is 
now usually checked by the compiler. We just have computational power to 
spare, so that the previously "costly" checking that was previously in a 
separate program called "lint", is now usually just part of the compiler 
proper. And with C++ a lot more is specified by the standard, than with 
C  --  after all, the C++ standard /includes/ the C standard.

Another way that the compiler is informed, is via C++ access 
restrictions and construction guarantees, plus rules about Undefined 
Behavior for code that does Unholy Things. However, to take advantage of 
that the compiler would have to do some higher level data flow and 
accessibility analysis. I think that it's doubtful that current 
compilers do that (because it's so easy for compiler writers to get 
stuck in lower level issues of parsing and parallelism and such, issues 
that were solved 50 years ago but that freshly graduated don't even know 
about), but as James Bond reportedly remarked, never say never.


[snip]

Cheers & hth.,

- Alf

0
usenet30 (890)
9/4/2012 1:10:02 PM
On 04/09/2012 15:10, Alf P. Steinbach wrote:
> On 04.09.2012 12:47, David Brown wrote:
>> On 03/09/2012 19:43, Richard Damon wrote:
>>> On 9/3/12 4:21 AM, David Brown wrote:
>>>> On 01/09/2012 15:39, Bo Persson wrote:
>>>>>
>>>>> Yes, the same index in two vectors can alias. Different index cannot.
>>>>>
>>>>
>>>> That doesn't make sense.  Are you saying that for two vectors v1 and
>>>> v2,
>>>> v1[10] and v2[10] can alias but v1[10] and v2[11] cannot?
>>>>
>>>
>>> v1 and v2 can be references to the same vector, and thus their
>>> corresponding elements alias. Since a vector has exclusive use of its
>>> "array" member storing its content, and has no operations that can yield
>>> a "sub vector" that references a partial section of the vector, there is
>>> no way for v1[10] and v2[11] to point to the same item.
>>>
>>> This is opposed to a built in array (passed via pointers) where v1 could
>>> have been set to &v2[1] and thus v1[10] and v2[11] alias.
>>>
>>
>> OK, I see that point now.
>>
>> However, while you (and now I) can understand that, I can't see any way
>> for the /compiler/ to know and take advantage of that.  There is no way
>> to tell the compiler that v1[10] and v2[11] are in different places.
>
> One way that the compiler is informed, is via the C++ standard.
>
> Which as opposed to the C standard, specifies a lot of higher level
> types in detail.
>
> However, even in C some higher level issues that are specified by the
> standard and cannot easily or at all be inferred from the code itself,
> such as correspondence between fprintf format strings and arguments, is
> now usually checked by the compiler. We just have computational power to
> spare, so that the previously "costly" checking that was previously in a
> separate program called "lint", is now usually just part of the compiler
> proper. And with C++ a lot more is specified by the standard, than with
> C  --  after all, the C++ standard /includes/ the C standard.
>
> Another way that the compiler is informed, is via C++ access
> restrictions and construction guarantees, plus rules about Undefined
> Behavior for code that does Unholy Things. However, to take advantage of
> that the compiler would have to do some higher level data flow and
> accessibility analysis. I think that it's doubtful that current
> compilers do that (because it's so easy for compiler writers to get
> stuck in lower level issues of parsing and parallelism and such, issues
> that were solved 50 years ago but that freshly graduated don't even know
> about), but as James Bond reportedly remarked, never say never.
>

You are right that the compiler can be told to treat the libraries in 
some special way - as many compilers generate faster code for functions 
like "memset" or "strcpy" than standard C definitions would give.  But I 
think it is a very difficult thing to do for general cases - it means 
lots of extra "special cases" handling in the compiler, and could cause 
endless problems for complex situations (such as when the user supplies 
some or all of the library themselves).

The way this sort of thing is (mostly) handled in gcc is by adding 
extensions.  For example, checking of printf format strings is indicated 
by using a set of function attributes in the header file declaration. 
This lets the compiler check the format string without having special 
handling for the library function, it lets the user write their own 
printf-style functions, and lets the user write a replacement printf 
without checking.

Of course, gcc also allows the "__restrict__" keyword in C++, allowing 
some of this already (though I don't know if it is used in the standard 
vector class or not).


0
david2384 (2168)
9/5/2012 9:24:44 AM
On Saturday, September 1, 2012 11:06:14 PM UTC-5, Anse wrote:
> John Bode wrote:
>=20
[snip]
> > C and C++ are different languages with a large common subset.=20
> > Why is that a problem?=20
>=20
> It's not common ENOUGH. Mostly, the C++ programmers will have to help the=
 C=20
> programmers adapt to a future that some of them will still see, lest they=
=20
> become the next wave of homeless when the <you know whos> kick them to th=
e=20
> curb. Making C/C++ more like one thing is like throwing a lifesaver to th=
e=20
> drowning C programmers.

Any programmer who is unable or unwilling to learn and adapt to the incompa=
tibilities between C and C++ (which will only diverge further over time) ne=
eds to get the hell out of software and find a new line of work, full stop.=
  If I can manage it, it ain't that goddamned hard to do. =20

Yes, it would be nice if every legal C program was also a legal C++ program=
 with identical semantics.  That ain't happening.  Ever.  Quit whining and =
deal with it or find another line of work.  
0
jfbode1029 (228)
9/5/2012 9:57:55 PM
FYGG.

Let's try that again.

On Wednesday, September 5, 2012 4:57:55 PM UTC-5, John Bode wrote: 
> 
> 
> Any programmer who is unable or unwilling to learn and adapt to the 
> incompatibilities between C and C++ (which will only diverge further 
> over time) needs to get the hell out of software and find a new line 
> of work, full stop.  If I can manage it, it ain't that goddamned hard 
> to do.  
> 
> Yes, it would be nice if every legal C program was also a legal C++ 
> program with identical semantics.  That ain't happening.  Ever.  
> Quit whining and deal with it or find another line of work.

0
jfbode1029 (228)
9/5/2012 10:29:44 PM
On Friday, August 31, 2012 3:53:54 PM UTC+3, Jens Gustedt wrote:
> Perhaps this got a bit lost in the discussion, but all of that started
> by trying to find replacements for "void*" in C++.

Why?   

> "void*" is a concept that works suitably well in C. It is just a
> nuisance in C++.

Not at all. Every raw pointer converts implicitly to void*. If you
need "a pointer" regardless of type at what it points then "void*"
is the thing to use. It is safer than some "unsigned char*". You
can not by some typo to do arithmetics or to dereference void*.

> > There is little use for 'void *' in pure C++ code,

Download the flagship template libraries collection called "boost". I 
bet you find hundreds of explicit usages of "void*" there if not
 thousands.

> > but it would still be required in the language to interface with C code.
> 
> Sure that was my starting point.

That is also one reason why it may be is needed, but far not the main one.
> 
> 
> 
> I even think that in C++ all conversion from "void*" to another type
> should and could be avoided. Basically I would say code that uses
> "void*" (manipulating pointers to void, or obfuscating types) are "C
> in disguise".

You can cast void* back into T* what it was with dynamic_cast<>() in
C++. dynamic_cast<>() does check runtime that the cast is correct.
It is very safe.

reinterpret_cast<>() of "unsigned char*" into T* is "C in disguise".

> I haven't heard of a good C++ use case, yet, that couldn't be packed
> into an 'extern "C"' interface and where the implementation then
> couldn't be done in proper C. A bit in the same spirit as some
> specific functions for OS or compilers are implemented in assembler.

I repeat. Just take boost. It is all good, well tested C++, mostly
header-only libraries. Open source. Free to eyeball and to use. Lot
of things from it went straight or with minor mods into C++2011.
Then come back and tell us how you reimplement that thing in 
C or assembler.
0
ootiib (965)
9/6/2012 2:41:01 AM
On Monday, September 3, 2012 12:14:18 AM UTC+3, Dombo wrote:
> Op 31-Aug-12 0:18, Jens Gustedt schreef:
> > Am 30.08.2012 19:49, schrieb Garrett Hartshaw:
> 
> >> If on the other hand you wish to have an opaque pointer to an object
> >> of unknown type, or to an uninitialized memory region, then use 'void *'.
> >
> > A "void*" pointer is not "an uninitialized" memory region. It may well
> > already be initialized.
> >
> > But I am really surprised about this strong need of opaque pointer in
> > C++. If we follow the basic ideas of C++ such a usage should be very
> > rare in C++, no? Isn't that what "abstract base classes" have been
> > invented for?

void* is the pointer to most abstract base class in C++. The base class
that is common to all classes and fundamental types.

> I've been programming C++ for almost 20 years now, I don't remember 
> having ever having a need to use void* other than to interface with C 
> code (typically when registering a callback on a C API, where context 
> information can be passed back to the callback function via a void*).

There are very different levels of usage of C++. When I use some
C++ framework like for example QT and only need the things that the
framework already provides then I will have next to no need for void*.
The typical uses in communication, serialization, containers,
encryption, compression, threads and signals are all provided by the
framework and the internal void* usage is hidden with templates
or code generators. When something so abstract and mundane is 
missing and I need to implement it for generic case then the need
for void* is there, nothing to replace it with.
0
ootiib (965)
9/6/2012 3:27:26 AM
On 09/05/2012 10:41 PM, � wrote:
> On Friday, August 31, 2012 3:53:54 PM UTC+3, Jens Gustedt wrote:
....
>> "void*" is a concept that works suitably well in C. It is just a
>> nuisance in C++.
> 
> Not at all. Every raw pointer converts implicitly to void*. If you
> need "a pointer" regardless of type at what it points then "void*"
> is the thing to use. It is safer than some "unsigned char*". You
> can not by some typo to do arithmetics or to dereference void*.

In C++, if you need "a pointer regardless of type", you can template on
T and use T*, for increased type safety on top of the same amount of
flexibility that void* gives you. As an additional bonus, you can do
(meaningful!) arithmetic on T* and even dereference it, which you can't
do with void*.

....
> You can cast void* back into T* what it was with dynamic_cast<>() in
> C++. dynamic_cast<>() does check runtime that the cast is correct.
> It is very safe.

Yes, it is safe, but dynamic_cast<T>(v) has a number of limitations: "T
shall be a pointer or reference to a complete class type, or “pointer to
cv void.”"(5.2.7p1), so it cannot be used to convert to, for instance,
double* or an opaque class type.

Also, "If T is a pointer type, v shall be an rvalue of a pointer to
complete class type ... If T is an lvalue reference type, v shall be an
lvalue of a complete class type ... If T is an rvalue reference type, v
shall be an expression having a complete class type ..." (5.2.7p2).
Notice that v cannot have type void*, because void is neither complete,
nor a class type.

>> I haven't heard of a good C++ use case, yet, that couldn't be packed
>> into an 'extern "C"' interface and where the implementation then
>> couldn't be done in proper C. A bit in the same spirit as some
>> specific functions for OS or compilers are implemented in assembler.
> 
> I repeat. Just take boost. It is all good, well tested C++, mostly
> header-only libraries. Open source. Free to eyeball and to use. Lot
> of things from it went straight or with minor mods into C++2011.
> Then come back and tell us how you reimplement that thing in 
> C or assembler.

He's not suggesting that the entire thing be implemented in C, only that
any place in the code which has a good reason for using void* could be
split into two parts: a part in C++ that makes no use of void*, and a
part that could be implemented entirely in C. His words also imply that
there might also be place where void* is used without there being a
"good C++ use case", in which case the code can probably be replaced,
not by C code, but by C++ code using T*, where T is a template type
parameter.

I don't know enough about boost internals to guess whether that would be
true, but it at least seems plausible to me.
-- 
James Kuyper
0
jameskuyper (5635)
9/6/2012 3:44:37 AM
On Thursday, September 6, 2012 6:44:40 AM UTC+3, James Kuyper wrote:
> On 09/05/2012 10:41 PM, =EF=BF=BD wrote:
> > On Friday, August 31, 2012 3:53:54 PM UTC+3, Jens Gustedt wrote:
> ...
> >> "void*" is a concept that works suitably well in C. It is just a
> >> nuisance in C++.
> >=20
> > Every raw pointer converts implicitly to void*. If you
> > need "a pointer" regardless of type at what it points then "void*"
> > is the thing to use. It is safer than some "unsigned char*". You
> > can not by some typo to do arithmetics or to dereference void*.
>=20
> In C++, if you need "a pointer regardless of type", you can template on
> T and use T*, for increased type safety on top of the same amount of
> flexibility that void* gives you. As an additional bonus, you can do
> (meaningful!) arithmetic on T* and even dereference it, which you can't
> do with void*.

In C++ a flexibility that is not needed is considered a bad thing. The
void* is anonymous. So when a part of software has not business to
know the nature or to dereference it then making it available is=20
wrong.

As similar example think of std::array<>. All it does compared to
usual array is that it removes implicit conversion to pointer and
wraps pointers into iterators. As result the code of usage compiles
into exactly same binary. Still it is lot safer because=20
dereferencing or doing arithmetics with it does not compile.

> > You can cast void* back into T* what it was with dynamic_cast<>() in
> > C++. dynamic_cast<>() does check runtime that the cast is correct.
> > It is very safe.
>=20
> Yes, it is safe, but dynamic_cast<T>(v) has a number of limitations: "T
> shall be a pointer or reference to a complete class type, or =E2=80=9Cpoi=
nter to
> cv void.=E2=80=9D"(5.2.7p1), so it cannot be used to convert to, for inst=
ance,
> double* or an opaque class type.

dynamic_cast<T>(v) has some runtime cost. So if you use pointers to=20
fundamental types in C++ then you likely are anyway seeking ways
to lower the cost that complete classes might have.
=20
> Also, "If T is a pointer type, v shall be an rvalue of a pointer to
> complete class type ... If T is an lvalue reference type, v shall be an
> lvalue of a complete class type ... If T is an rvalue reference type, v
> shall be an expression having a complete class type ..." (5.2.7p2).
> Notice that v cannot have type void*, because void is neither complete,
> nor a class type.

To void* one should cast implicitly. Explicit cast looks not good
like casting away constness and other such things.

> >> I haven't heard of a good C++ use case, yet, that couldn't be packed
> >> into an 'extern "C"' interface and where the implementation then
> >> couldn't be done in proper C. A bit in the same spirit as some
> >> specific functions for OS or compilers are implemented in assembler.
> >=20
> > I repeat. Just take boost. It is all good, well tested C++, mostly
> > header-only libraries. Open source. Free to eyeball and to use. Lot
> > of things from it went straight or with minor mods into C++2011.
> > Then come back and tell us how you reimplement that thing in=20
> > C or assembler.
>=20
> He's not suggesting that the entire thing be implemented in C, only that
> any place in the code which has a good reason for using void* could be
> split into two parts: a part in C++ that makes no use of void*, and a
> part that could be implemented entirely in C.

The C++ itself can wrap and hide void* usage lot better than in
cooperation with C.

> His words also imply that
> there might also be place where void* is used without there being a
> "good C++ use case", in which case the code can probably be replaced,
> not by C code, but by C++ code using T*, where T is a template type
> parameter.

There certainly are lot of bad C++ code where void* or preprocessor
macros should be replaced with templates. void* is a tool like any
other. You can use it in harmful way. That is not the case with boost.

> I don't know enough about boost internals to guess whether that would be
> true, but it at least seems plausible to me.

Boost is mostly header-only, the void* is mostly used privately.
With C it would drop being header only or the void* usage would
become public.=20
0
ootiib (965)
9/6/2012 6:08:08 AM
On 09/06/2012 02:08 AM, � wrote:
> On Thursday, September 6, 2012 6:44:40 AM UTC+3, James Kuyper wrote:
>> On 09/05/2012 10:41 PM, � wrote:
>>> On Friday, August 31, 2012 3:53:54 PM UTC+3, Jens Gustedt wrote:
....
[Re: C++ restrictions on dynamic_cast<T>(v)]
>> Also, "If T is a pointer type, v shall be an rvalue of a pointer to
>> complete class type ... If T is an lvalue reference type, v shall be an
>> lvalue of a complete class type ... If T is an rvalue reference type, v
>> shall be an expression having a complete class type ..." (5.2.7p2).
>> Notice that v cannot have type void*, because void is neither complete,
>> nor a class type.
> 
> To void* one should cast implicitly. ...

In that paragraph, I'm talking about conversion from void*, not
conversion to void*. Implicit conversion from void* to a pointer to an
object type is allowed by C, but not by C++.

> ... Explicit cast looks not good
> like casting away constness and other such things.

dynamic_cast<T>(v) shall not be used to cast away constness (5.2.7p1).
-- 
James Kuyper
0
jameskuyper (5635)
9/6/2012 11:07:53 AM
On Thursday, September 6, 2012 2:07:55 PM UTC+3, James Kuyper wrote:
> On 09/06/2012 02:08 AM, =EF=BF=BD wrote:
> > On Thursday, September 6, 2012 6:44:40 AM UTC+3, James Kuyper wrote:
> >> Notice that v cannot have type void*, because void is neither complete=
,
> >> nor a class type.
> >=20
> > To void* one should cast implicitly. ...
>=20
> In that paragraph, I'm talking about conversion from void*, not
> conversion to void*. Implicit conversion from void* to a pointer to an
> object type is allowed by C, but not by C++.

Ok, my bad. You are correct. A proper C++ compiler just does not let me.
If it lets to dynamic cast from void* then it is some sort of extension aga=
in.
0
ootiib (965)
9/6/2012 4:40:20 PM
James Kuyper <jameskuyper@verizon.net> writes:

> On 08/28/2012 09:32 AM, David Brown wrote:
> ...
>> Ultimately, I'd like some way to tell the compiler what data, pointers 
>> and/or types can alias what.
>
> If you put two types in a union, within the scope of that union
> declaration a conforming implementation must take aliasing between those
> two types into consideration any time it's dealing with pointers that
> could be pointing at different members of the same union object.

Obviously this isn't right, since if it were there
would be no reason for the "one special guarantee"
for structure access.
0
txr1 (1467)
9/7/2012 12:41:32 PM
Keith Thompson <kst-u@mib.org> writes:

> Kenneth Brody <kenbrody@spamcop.net> writes:
>> On 8/30/2012 8:30 PM, Keith Thompson wrote:
>>> Jens Gustedt <jens.gustedt@loria.fr> writes:
>> [...]
>>>> so "void*" says pointer to void. This is not "nothing" or "unknown",
>>>> in that sense void is not much different from "struct nix" when you
>>>> never actually define "struct nix" somewhere. It behaves a bit
>>>> different in terms of implicit conversions, sure, but the sematic is
>>>> the same.
>>>
>>> Not really.  A `char*` pointer points to an object of type `char`.  A
>>> `void*` pointer does not point to an object of type `void`, because
>>> there is no such thing.
>>>
>>> Any type of pointer to object or incomplete type (i.e., any pointer
>>> other than a function pointer) points to some object in memory (or to
>>> nothing if it's currently a null pointer).  What's special about `void*`
>>> is that, while you can perform certain pointer operations on it, you
>>> can't access the object it points to without first converting it to some
>>> other pointer type.
>> [...]
>>
>> While technically correct that "void *" doesn't point to an object of
>> type "void" because there's no such thing, I think it is convenient to
>> think of it in those terms.
>
> I disagree.  That is, I agree that it's technically correct (the
> best kind of correct!), but I think it's correct in every other
> sense as well.  [snip elaboration]

I would say exactly the opposite - a pointer of type 'void *'
points at something of type void.  In fact all valid addresses
(arguably even those pointing past the end of arrays) refer
to legimate void objects.  Just because you can't /do/ anything
with those void objects, as such, doesn't make them any less
legimate.

To give a more concrete argument, the rules for derived types,
in particular pointer types, says "A pointer type describes an
object whose value provides a reference to an entity of the
referenced type."  There is no special mention or exception
made for pointers to void.
0
txr1 (1467)
9/7/2012 12:57:38 PM
David Brown <david@westcontrol.removethisbit.com> writes:

> On 28/08/2012 18:39, James Kuyper wrote:
>> On 08/28/2012 09:32 AM, David Brown wrote:
>> ...
>>> Ultimately, I'd like some way to tell the compiler what data, pointers
>>> and/or types can alias what.
>>
>> If you put two types in a union, within the scope of that union
>> declaration a conforming implementation must take aliasing between those
>> two types into consideration any time it's dealing with pointers that
>> could be pointing at different members of the same union object.
>>
>
> Correct me if I'm wrong, but I believe this is actually just an
> "unwritten rule" that all compilers have agreed to follow. [snip]

Actually it (ie, the semantics of union member access) is a written
rule, it's just not written in a way that makes it obvious.
0
txr1 (1467)
9/7/2012 1:03:14 PM
Jens Gustedt <jens.gustedt@loria.fr> writes:

> Am 29.08.2012 10:44, schrieb David Brown:
>> On 29/08/2012 10:19, Jens Gustedt wrote:
>> The great thing about standards is that there are so many to choose from!
>
> :)
>
>> I don't know that type-punning was the "main intent" of unions - I think
>> saving storage space was the main motivation.
>
> I was perhaps pushing a bit too far, but type punning has been around
> since the beginning. And if I understand it right it was the idea of
> the committee to affirm that it always had been an intented use case,
> and that just the wording in the standard had been too ambiguous.
> [snip unrelated]

The phrasing in C90 made the type punning semantics obvious.
The original wording in C99 had the same semantics as was
intended for C90, but this was not obvious.  The DR that
introduced the clarifying footnote makes it clear that
there was no change in intention, only a change in wording.

0
txr1 (1467)
9/7/2012 1:13:06 PM
Keith Thompson <kst-u@mib.org> writes:

> Jens Gustedt <jens.gustedt@loria.fr> writes:
> [...]
>> 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), [snip]

If you look near the top of the page the footnote is on,
you should find the change bar next to paragraph 3,
to show that the footnote was added.
0
txr1 (1467)
9/7/2012 1:17:04 PM
"Ansel" <tinker454@trytospammenowloser.com> writes:

> Isn't it a lame use of human time and effort to maintain completely separate 
> C and C++ standards? 

No.
0
txr1 (1467)
9/7/2012 1:18:28 PM
Tim Rentsch <txr@alumni.caltech.edu> writes:
> Keith Thompson <kst-u@mib.org> writes:
>> Kenneth Brody <kenbrody@spamcop.net> writes:
[...]
>>> While technically correct that "void *" doesn't point to an object of
>>> type "void" because there's no such thing, I think it is convenient to
>>> think of it in those terms.
>>
>> I disagree.  That is, I agree that it's technically correct (the
>> best kind of correct!), but I think it's correct in every other
>> sense as well.  [snip elaboration]
>
> I would say exactly the opposite - a pointer of type 'void *'
> points at something of type void.  In fact all valid addresses
> (arguably even those pointing past the end of arrays) refer
> to legimate void objects.  Just because you can't /do/ anything
> with those void objects, as such, doesn't make them any less
> legimate.

So you believe that there's such a thing as a "void object"?

An "object" is by definition a "region of data storage in the
execution environment, the contents of which can represent values".
For a void object, what is the size of this region, and what values
can its contents represent?

> To give a more concrete argument, the rules for derived types,
> in particular pointer types, says "A pointer type describes an
> object whose value provides a reference to an entity of the
> referenced type."  There is no special mention or exception
> made for pointers to void.

Or for pointers to other incomplete types, or for null pointers.
I suggest that this is an oversight.  I'll also note that it uses
the word "entity", not "object".  Neither void pointers nor function
pointers refer to objects.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
9/7/2012 9:17:48 PM
Tim Rentsch <txr@alumni.caltech.edu> writes:
> Keith Thompson <kst-u@mib.org> writes:
>> Jens Gustedt <jens.gustedt@loria.fr> writes:
>> [...]
>>> 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), [snip]
>
> If you look near the top of the page the footnote is on,
> you should find the change bar next to paragraph 3,
> to show that the footnote was added.

You're right (though it would have made sense to have a change bar on
the footnote itself as well).

For those following along, this is footnote 82, section 6.5.2.3p3 in
N1256, foonote 95, same section in N1570.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
9/7/2012 9:22:31 PM
Keith Thompson <kst-u@mib.org> writes:

> Tim Rentsch <txr@alumni.caltech.edu> writes:
>> Keith Thompson <kst-u@mib.org> writes:
>>> Kenneth Brody <kenbrody@spamcop.net> writes:
> [...]
>>>> While technically correct that "void *" doesn't point to an object of
>>>> type "void" because there's no such thing, I think it is convenient to
>>>> think of it in those terms.
>>>
>>> I disagree.  That is, I agree that it's technically correct (the
>>> best kind of correct!), but I think it's correct in every other
>>> sense as well.  [snip elaboration]
>>
>> I would say exactly the opposite - a pointer of type 'void *'
>> points at something of type void.  In fact all valid addresses
>> (arguably even those pointing past the end of arrays) refer
>> to legimate void objects.  Just because you can't /do/ anything
>> with those void objects, as such, doesn't make them any less
>> legimate.
>
> So you believe that there's such a thing as a "void object"?

Sure.  void is an object type -- an incomplete object type, but
still an object type.  What's wrong with having there be void
objects?

> An "object" is by definition a "region of data storage in the
> execution environment, the contents of which can represent values".
> For a void object, what is the size of this region, and what values
> can its contents represent?

Same answers as for 'struct foo' when that is an incoomplete
type, namely, we don't know and we don't know.  One thing
we _do_ know that is very useful is where the object starts.

>> To give a more concrete argument, the rules for derived types,
>> in particular pointer types, says "A pointer type describes an
>> object whose value provides a reference to an entity of the
>> referenced type."  There is no special mention or exception
>> made for pointers to void.
>
> Or for pointers to other incomplete types, or for null pointers.

Pointers to incomplete object types still refer to objects.

The null pointer case is a red herring, just like a pointer
to one-past-an-array - the pointer still provides a reference
to something of the referenced type, even if in some cases
we can't actually get a "thing" by dereferencing.  We can't
get a "thing" by dereferencing a pointer to an incomplete
object type either, but there still can be an object there
of that type even if we don't know what it is.

> I suggest that this is an oversight.  I'll also note that it uses
> the word "entity", not "object".  Neither void pointers nor function
> pointers refer to objects.

The word "entity" is used only because functions and objects
are different.  A pointer-to-function refers to a function;
a pointer to an object type refers to an object, whether
it is of complete object type or incomplete object type.

The world is just a lot simpler if we assume that there are void
objects along with all the other kinds of objects.  I'm sure a
consistent model can be constructed where a pointer-to-void
points to "nothing", but why would we do that when it will just
complicate things?  For example, converting a pointer to a
pointer-to-character type gives a pointer to the first byte of
the object.  If a (void*) pointer points to "nothing", converting
it to a (char*) will end up being undefined behavior.  Those
kinds of problems seem like a big headache for no tangible value.
0
txr1 (1467)
9/8/2012 2:37:33 AM
Keith Thompson <kst-u@mib.org> wrote:
> Tim Rentsch <txr@alumni.caltech.edu> writes:
> > Keith Thompson <kst-u@mib.org> writes:
> >>
> >> Yes.  That footnote was added by Technical Corrigendum 3.  It appears
> >> in N1256 (though oddly without a change bar), [snip]
> >
> > If you look near the top of the page the footnote is on,
> > you should find the change bar next to paragraph 3,
> > to show that the footnote was added.
> 
> You're right (though it would have made sense to have a change bar on
> the footnote itself as well).

Indeed. The automated diff mark process falls down in this case due to
the way footnotes are handled in troff and mm. The editor usualy makes
an effort to correct such misses manually, but managed to overlook that
one.
-- 
Larry Jones

It's either spectacular, unbelievable success, or crushing, hopeless
defeat!  There is no middle ground! -- Calvin
0
9/10/2012 9:21:21 PM
Malcolm McLean <malcolm.mclean5@btinternet.com> wrote:
> 
> Yes, we badly need one programming language that does everything.

What you'll get is a programming language that does everything badly.
-- 
Larry Jones

I can feel my brain beginning to atrophy already. -- Calvin
0
9/11/2012 3:14:25 PM
=D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=A9=D7=9C=D7=99=
=D7=A9=D7=99, 11 =D7=91=D7=A1=D7=A4=D7=98=D7=9E=D7=91=D7=A8 2012 16:14:25 U=
TC+1, =D7=9E=D7=90=D7=AA lawrenc...@siemens.com:
> Malcolm McLean <malcolm.mclean5@btinternet.com> wrote:=20
>=20
> > Yes, we badly need one programming language that does everything.
>=20
>=20
> What you'll get is a programming language that does everything badly.
>=20
That's arguably OK. Better to do every badly, but at least work, everywhere=
, than have a finely honed, expensively developed, very interesting program=
, in Lisp.
0
9/11/2012 10:14:09 PM
On Sep 11, 11:14=C2=A0pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
wrote:
> =D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=A9=D7=9C=D7=
=99=D7=A9=D7=99, 11 =D7=91=D7=A1=D7=A4=D7=98=D7=9E=D7=91=D7=A8 2012 16:14:2=
5 UTC+1, =D7=9E=D7=90=D7=AA lawrenc...@siemens.com:> Malcolm McLean <malcol=
m.mcle...@btinternet.com> wrote:
>
> > > Yes, we badly need one programming language that does everything.
>
> > What you'll get is a programming language that does everything badly.
>
> That's arguably OK. Better to do every badly, but at least work, everywhe=
re, than have a finely honed, expensively developed, very interesting progr=
am, in Lisp.

oh. I assumed you were proposing Lisp *as* the universal hammer. Which
blub are you proposing then? PL/I was the last attempt.
0
9/12/2012 8:01:52 AM
=D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=A8=D7=91=D7=99=
=D7=A2=D7=99, 12 =D7=91=D7=A1=D7=A4=D7=98=D7=9E=D7=91=D7=A8 2012 09:01:53 U=
TC+1, =D7=9E=D7=90=D7=AA Nick Keighley:
> On Sep 11, 11:14=C2=A0pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
>=20
> oh. I assumed you were proposing Lisp *as* the universal hammer. Which=20
> blub are you proposing then? PL/I was the last attempt.
>
I'd say it needs essentially C syntax - loops, curly brackets, non-flow con=
trol non-arithemtical functionality implemented as functions rather than th=
e core language. That's generally been accepted.

But C itself isn't a good universal language, because of the buffer overflo=
w and wild pointer issue. Also because of the difficulties in representing =
higher-level contructs, like classes, graphs, and metacode. Even structs ha=
ve no way of serialising without writing special functions for each case.

Also the proliferation of integer types is unacceptable.

0
9/12/2012 11:40:25 AM
On Sep 12, 12:40=C2=A0pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
wrote:
> =D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=A8=D7=91=D7=
=99=D7=A2=D7=99, 12 =D7=91=D7=A1=D7=A4=D7=98=D7=9E=D7=91=D7=A8 2012 09:01:5=
3 UTC+1, =D7=9E=D7=90=D7=AA Nick Keighley:> On Sep 11, 11:14=C2=A0pm, Malco=
lm McLean <malcolm.mcle...@btinternet.com>

Malcolm Mclean said
>>> Yes, we badly need one programming language that does everything.

apparently for small values of "everything"


> > oh. I assumed you were proposing Lisp *as* the universal hammer. Which
> > blub are you proposing then? PL/I was the last attempt.
>
> I'd say it needs essentially C syntax - loops, curly brackets, non-flow c=
ontrol non-arithemtical functionality implemented as functions rather than =
the core language. That's generally been accepted.

by whom? You seem to saying we need a single low level procedural
language. I'm not sure your wish-list is consistent. lets call it
Single Procedural Language (SPL)

> But C itself isn't a good universal language, because of the buffer overf=
low and wild pointer issue.

use Java? But that interposes a VM. How do you avoid buffer overflow
without runtime overhead? Could we write a device driver in SPL? What
about cryto, compression or embedded code?

> Also because of the difficulties in representing higher-level contructs, =
like classes, graphs, and metacode.

templates? Can even Java do all these things?

> Even structs have no way of serialising without writing special functions=
 for each case.

Java? Python? Sounds potentially expensive

> Also the proliferation of integer types is unacceptable.

but also useful. is there a current langauage thate meets your
criteria?

0
9/12/2012 1:31:17 PM
On 09/12/2012 09:31 AM, Nick Keighley wrote:
> On Sep 12, 12:40 pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
> wrote:
....
>>>> Yes, we badly need one programming language that does everything.
....
> ... is there a current langauage thate meets your
> criteria?

I believe that "we badly need" implies that he knows of no such language.
0
jameskuyper (5635)
9/12/2012 2:16:16 PM
On Sep 12, 3:16=A0pm, James Kuyper <jameskuy...@verizon.net> wrote:
> On 09/12/2012 09:31 AM, Nick Keighley wrote:
>
> > On Sep 12, 12:40 pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
> > wrote:
> ...
> >>>> Yes, we badly need one programming language that does everything.
> ...
> > ... is there a current langauage thate meets your
> > criteria?
>
> I believe that "we badly need" implies that he knows of no such language.

ok. is there one that matches most of the requirement? I'm dubious
that a language can have address safety, generics, metacode and
builtit serialization whilst still preserving the low level access
that is one of C's powers.
0
9/12/2012 2:27:20 PM
=D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=A8=D7=91=D7=99=
=D7=A2=D7=99, 12 =D7=91=D7=A1=D7=A4=D7=98=D7=9E=D7=91=D7=A8 2012 14:31:18 U=
TC+1, =D7=9E=D7=90=D7=AA Nick Keighley:
> On Sep 12, 12:40=C2=A0pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
>=20
>> I'd say it needs essentially C syntax - loops, curly brackets, non-flow=
=20
>> control non-arithemtical functionality implemented as functions rather t=
han >> the core language. That's generally been accepted.
>=20
>=20
> by whom? You seem to saying we need a single low level procedural
> language. I'm not sure your wish-list is consistent. lets call it
> Single Procedural Language (SPL)
>=20
Most modern new languages go for curly braces and a superfically at least=
=20
C-like syntax. But there are exceptions, of course. If there were no except=
ions
at all then saying "we need essential C-like syntax" would be as fatuous as
saying "we should standardise on Arabic numerals".
0
9/12/2012 2:58:39 PM
"Malcolm McLean" <malcolm.mclean5@btinternet.com> wrote in message
news:7073a8f9-488c-4f6a-9a32-42e8f2b161cc@googlegroups.com...
> בתאריך יום רביעי, 12 בספטמבר 2012 09:01:53 UTC+1, מאת Nick Keighley:
>> On Sep 11, 11:14 pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
>>
>> oh. I assumed you were proposing Lisp *as* the universal hammer. Which
>> blub are you proposing then? PL/I was the last attempt.
>>
> I'd say it needs essentially C syntax - loops, curly brackets, non-flow
> control non-arithemtical functionality implemented as functions rather
> than the core language. That's generally been accepted.

Not by everyone. Or it's been forced on them. A number of syntax styles are
possible for a given language, of which C-style is one, characterised by too
much punctuation and lots of curly braces.

> Also the proliferation of integer types is unacceptable.

Proliferation? Typically there are 8 combinations of signed/unsigned, and
width (8,16,32,64 bits). For discrete int variables, you might only use one
or two. For packed arrays and structs, you need to have the choice.

> But C itself isn't a good universal language, because of the buffer
> overflow and wild pointer issue. Also because of the difficulties in
> representing higher-level contructs, like classes, graphs, and metacode.
> Even structs have no way of serialising without writing special functions
> for each case.

No, C is hopeless. There are plenty of improvements that can be made(**),
but you will just end up with some ghastlier version of C++. I don't believe
a single universal language can be created that will please everyone.

(** I recently finished designing a low-level implementation language that
pretty much does what C does. When I listed the differences (mostly
improvements in my view!) from C, I stopped when I got to 100. And that
didn't include syntax which is utterly different. But then, it's not hard to
tidy up a language that's 40 years old.)

-- 
Bartc 

0
bc (2337)
9/12/2012 3:21:59 PM
=D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=A8=D7=91=D7=99=
=D7=A2=D7=99, 12 =D7=91=D7=A1=D7=A4=D7=98=D7=9E=D7=91=D7=A8 2012 16:22:06 U=
TC+1, =D7=9E=D7=90=D7=AA Bart:
> "Malcolm McLean" <malcolm.mclean5@btinternet.com> wrote in message
>=20
>=20
> Proliferation? Typically there are 8 combinations of signed/unsigned, and
> width (8,16,32,64 bits). For discrete int variables, you might only use o=
ne
> or two. For packed arrays and structs, you need to have the choice.
>=20
Consider this

int16 *readaudiosamples(void *context);
void playaudiosamples(short *wave, int N);

0
9/12/2012 5:21:38 PM

"Malcolm McLean" <malcolm.mclean5@btinternet.com> wrote in message
news:bfbe86f3-a190-48c4-be35-ab22ec5b3876@googlegroups.com...
> בתאריך יום רביעי, 12 בספטמבר 2012 16:22:06 UTC+1, מאת Bart:
>> "Malcolm McLean" <malcolm.mclean5@btinternet.com> wrote in message
>>
>>
>> Proliferation? Typically there are 8 combinations of signed/unsigned, and
>> width (8,16,32,64 bits). For discrete int variables, you might only use
>> one
>> or two. For packed arrays and structs, you need to have the choice.
>>
> Consider this
>
> int16 *readaudiosamples(void *context);
> void playaudiosamples(short *wave, int N);

What about it?

Audio probably *is* best handled as blocks of 16-bit data. But the example
uses 3 different int denotations, with probably two different widths; is
that the trouble?

I've already made the point that C could be improved, with regard to
managing these various different types. But I doubt whether you're seriously
proposing using actual C syntax, rather than C-style, as the basis for your 
universal language.

-- 
Bartc 

0
bc (2337)
9/12/2012 5:59:45 PM
On 09/12/2012 11:21 AM, BartC wrote:
> "Malcolm McLean" <malcolm.mclean5@btinternet.com> wrote in message
> news:7073a8f9-488c-4f6a-9a32-42e8f2b161cc@googlegroups.com...
....
>> Also the proliferation of integer types is unacceptable.
> 
> Proliferation? Typically there are 8 combinations of signed/unsigned, and
> width (8,16,32,64 bits).

I count a lot more than 8. There's a minimum of 12 integer types that
must be distinct on all implementations (even though one pair of them
must have the same size, alignment requirement and representation, and
other pairs might also match):
_Bool
[unsigned | (plain) | signed] char: 3
[unsigned | signed] [short | int | long | long long]: 8

Each of the following types could be the same as one of the above, or a
distinct extended integer type:
[u]intN_t: none  mandatory
[u]int_leastN_t: 8 mandatory
[u]int_fastN_t: 8 mandatory
[u]intmax_t: 2
[u]intprt_t: 2
size_t, ptrdiff_t, wchar_t, char16_t, char32_t
atomic_ versions of all of the above: total of 37 mandatory.
sig_atomic_t, wint_t

That's a total of 74 mandatory types that are required to be integers,
and in principle they could all be distinct types.

In addition, all of the following types could be integer types (though
they don't have to be), and don't have to be the same as any of the above:
fpos_t, cnd_t, thrd_t, tss_t, mtx_t, clock_t, time_t, max_align_t,
mbstate_t, wctrans_t, wctype_t

The important thing is not that they could all be distinct - that's
highly unlikely - in all likelihood they span not much more than a dozen
distinct types. The important point is that it's difficult, in general,
to determine which ones are the same. It used to be impossible, but the
new _Generic feature of C2011 makes it possible, at least at run time,
if not at compile time. However, it's still not easy)


0
jameskuyper (5635)
9/12/2012 6:01:43 PM
Malcolm McLean <malcolm.mclean5@btinternet.com> writes:
> בתאריך יום רביעי, 12 בספטמבר 2012 09:01:53 UTC+1, מאת Nick Keighley:
>> On Sep 11, 11:14 pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
>> 
>> oh. I assumed you were proposing Lisp *as* the universal hammer. Which 
>> blub are you proposing then? PL/I was the last attempt.
>>
> I'd say it needs essentially C syntax - loops, curly brackets,
> non-flow control non-arithemtical functionality implemented as
> functions rather than the core language. That's generally been
> accepted.

No, it hasn't.  There are a number of different syntaxes for
delimiting compound statements in modern languages: {/} (C, C++,
Perl et al), begin/end (Ada et al), and indentation (Python et al)
spring to mind, and there are variations on each.  I don't find
any of these clearly superior to the others.

[...]

> Also the proliferation of integer types is unacceptable.

It's nearly unavoidable if you're going to (a) support types
matching the various widths of integers supported by hardware, and
(b) permit the use of types whose width can vary from platform to
another (size_t, for example).

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
9/12/2012 6:42:07 PM
"James Kuyper" <jameskuyper@verizon.net> wrote in message 
news:5050CE07.3000307@verizon.net...
> On 09/12/2012 11:21 AM, BartC wrote:
>> "Malcolm McLean" <malcolm.mclean5@btinternet.com> wrote in message
>> news:7073a8f9-488c-4f6a-9a32-42e8f2b161cc@googlegroups.com...
> ...
>>> Also the proliferation of integer types is unacceptable.
>>
>> Proliferation? Typically there are 8 combinations of signed/unsigned, and
>> width (8,16,32,64 bits).
>
> I count a lot more than 8. There's a minimum of 12 integer types that
> must be distinct on all implementations (even though one pair of them
> must have the same size, alignment requirement and representation, and
> other pairs might also match):
> _Bool
> [unsigned | (plain) | signed] char: 3
> [unsigned | signed] [short | int | long | long long]: 8
>
> Each of the following types could be the same as one of the above, or a
> distinct extended integer type:
> [u]intN_t: none  mandatory
> [u]int_leastN_t: 8 mandatory
> [u]int_fastN_t: 8 mandatory
> [u]intmax_t: 2
> [u]intprt_t: 2
> size_t, ptrdiff_t, wchar_t, char16_t, char32_t
> atomic_ versions of all of the above: total of 37 mandatory.
> sig_atomic_t, wint_t
>
> That's a total of 74 mandatory types that are required to be integers,
> and in principle they could all be distinct types.

This is just C trying to make things difficult.

I thought Malcolm was suggesting the use of a single int type instead of the 
four common widths supported by many CPUs (plus signed/unsigned variations). 
Perhaps dealing with all my eight types isn't a big deal after all..

In your list, I wouldn't include _Bool as an 'int' type; it can be 
considered a type in it's own right. While the char types are just synonyms 
for ints, really (unless they behave in any way differently to an int of the 
same width and sign?).

And on typical machines I use, char is 8 bits, short is 16 bits, int is 32 
bits, and long long is 64 bits.

'long' seems to be either 32 or 64 bits. (Maybe there are machines that use 
odd sizes such as 24/48 bits, or that support 96/128-bit ints, but not 
'typical'.)

Everything else is imposed by the language (including all those UINT_MINs 
and INT_MAXs). I doubt a 'universal' language would use the same approach.

(I use 'int' and 'word' for signed/unsigned integers of natural width; int:N 
and word:N for specific bitwidths, and int*N and byte*N for specific 
bytewidths; while 'byte' is a synonym for word:8. For value ranges, I use 
int.min, word.max and so on.)

-- 
Bartc 

0
bc (2337)
9/12/2012 7:36:54 PM
On 09/12/2012 03:36 PM, BartC wrote:
> "James Kuyper" <jameskuyper@verizon.net> wrote in message 
> news:5050CE07.3000307@verizon.net...
....
>> I count a lot more than 8. There's a minimum of 12 integer types that
>> must be distinct on all implementations (even though one pair of them
>> must have the same size, alignment requirement and representation, and
>> other pairs might also match):
>> _Bool
>> [unsigned | (plain) | signed] char: 3
>> [unsigned | signed] [short | int | long | long long]: 8
>>
>> Each of the following types could be the same as one of the above, or a
>> distinct extended integer type:
>> [u]intN_t: none  mandatory
>> [u]int_leastN_t: 8 mandatory
>> [u]int_fastN_t: 8 mandatory
>> [u]intmax_t: 2
>> [u]intprt_t: 2
>> size_t, ptrdiff_t, wchar_t, char16_t, char32_t
>> atomic_ versions of all of the above: total of 37 mandatory.
>> sig_atomic_t, wint_t
>>
>> That's a total of 74 mandatory types that are required to be integers,
>> and in principle they could all be distinct types.
> 
> This is just C trying to make things difficult.
> 
> I thought Malcolm was suggesting the use of a single int type instead of the 

In a C context, 'int' is the name of a specific type, and a component
(usually optional) of the names of several other types, but it is not an
adjective. The adjective you're looking for is "integer", not "int".

> four common widths supported by many CPUs (plus signed/unsigned variations). 
> Perhaps dealing with all my eight types isn't a big deal after all..

Malcolm does indeed believe in having a single integer type.  I don't. I
agree with him that there are too many integer types, but he would trim
the type system far more than I would, if either of us had to the power
to do so without worrying about backwards compatibility.

> In your list, I wouldn't include _Bool as an 'int' type; it can be 
> considered a type in it's own right.

It is considered a type in it's own right, but like most other types,
that type is also defined by the standard as being a member of a
specific type category, the standard unsigned integer types (6.2.5p6).
As a result, it is also a member of several other standard-defined type
categories: unsigned integer types, integer types, basic types, real
types, arithmetic types, and scalar types. (6.2.5)

> ... While the char types are just synonyms 
> for ints, really (unless they behave in any way differently to an int of the 
> same width and sign?).

The char types are integer types (6.2.5p17). The [u]int8_t and
[u]int_*8_t types are likely to be typedefs for char types on any
machine with CHAR_BIT==8, but calling 'unsigned char" a synonym for
uint_least8_t reverses the roles of the two types.

> And on typical machines I use, char is 8 bits, short is 16 bits, int is 32 
> bits, and long long is 64 bits.

I've already acknowledged that the 12 integer types that a conforming
implementation of C is required to support as distinct types need not
have distinct characteristics. In fact, plain char is required to have
exactly the same characteristics as either "signed char" or "unsigned
char". The important point is that, while some of them might be
implemented identically, the standard still requires that they all be
treated as distinct types, and there's no guarantees as to which pairs
of types are implemented identically. For the full set of types I listed
above, many of them are likely to be aliases for one of the 12 mandatory
types. On implementations with extended integer types, many pairs of the
other types I listed are likely to be aliases for the same extended
integer type. However, the key point is that there's no pairs in that
list which are guaranteed to be aliases for the same type; portable code
must assume that any two of them might be distinct types.

....
> (I use 'int' and 'word' for signed/unsigned integers of natural width; int:N 
> and word:N for specific bitwidths, and int*N and byte*N for specific 
> bytewidths; while 'byte' is a synonym for word:8. For value ranges, I use 

I strongly recommend against using non-standard definitions for terms
defined by the C standard such as 'int' and 'byte' in this newsgroup -
it can only lead to confusion. 'int' is a C standard type, which need
not have what you consider the "natural width". The C standard defines
'byte' as an "addressable unit of data storage large enough to hold any
member of the basic character set of the execution environment"; if
CHAR_BIT != 8, that doesn't match your definition.

The standard doesn't define a meaning for 'word', so that's one you can
freely muck around with.

0
jameskuyper (5635)
9/12/2012 8:57:03 PM
=D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=A8=D7=91=D7=99=
=D7=A2=D7=99, 12 =D7=91=D7=A1=D7=A4=D7=98=D7=9E=D7=91=D7=A8 2012 20:57:10 U=
TC+1, =D7=9E=D7=90=D7=AA Bart:
> "James Kuyper" <jameskuyper@verizon.net> wrote in message=20
>=20
> I thought Malcolm was suggesting the use of a single int type instead of =
the=20
> four common widths supported by many CPUs (plus signed/unsigned variation=
s).=20
>
> Perhaps dealing with all my eight types isn't a big deal after all..
>=20
Most data is integers, strings, reals or enums. Beyond that level of granul=
arity
it becomes very domain-specific. There's a tension between the needs of the
machine and the needs of the data. In a universal computer languge, the lin=
e=20
would have to be drawn to empahsise the needs of the data.
0
9/12/2012 9:18:12 PM
On Sep 1, 10:29=A0pm, "Anse" <blankon...@framebuilder.net> wrote:
> Kaz Kylheku wrote:
<snip>
> > Just say no to these clowns.
>
> Most are actually pretty darned smart. But when they start on their "spie=
l",
> I give it right back to them and then some, but they do not seem to be
> learning from it. I think they see everything as a pissing contest. Have =
you
> ever seen a C or C++ programmer admit that they were wrong or that someon=
e
> else actually has a good point? They see everything as a threat. I guess
> that is what a focus on sports in schools and fraterneties result in. Sig=
h.
> I think this is why much of the world sees "Americans" as stupid. Which, =
of
> course, begs the question, "Is USA's largest export, stupidity?".
>

1. So does this mean everyone in the entire "rest of the world" is
"not stupid"
in this way, and _ONLY_ Americans are?

2. Are _all_ the C/C++ programmers who refuse to admit they're wrong
or that
others' points are good, American?
0
mike4ty4 (440)
9/12/2012 10:40:55 PM
"James Kuyper" <jameskuyper@verizon.net> ha scritto nel messaggio
news:5050CE07.3000307@verizon.net...
> On 09/12/2012 11:21 AM, BartC wrote:
>> "Malcolm McLean" <malcolm.mclean5@btinternet.com> wrote in message
>> news:7073a8f9-488c-4f6a-9a32-42e8f2b161cc@googlegroups.com...
> ...
>>> Also the proliferation of integer types is unacceptable.
>>
>> Proliferation? Typically there are 8 combinations of signed/unsigned, and
>> width (8,16,32,64 bits).
>
> I count a lot more than 8. There's a minimum of 12 integer types that
> must be distinct on all implementations (even though one pair of them
> must have the same size, alignment requirement and representation, and
> other pairs might also match):
> _Bool
> [unsigned | (plain) | signed] char: 3
> [unsigned | signed] [short | int | long | long long]: 8
>
> Each of the following types could be the same as one of the above, or a
> distinct extended integer type:
> [u]intN_t: none  mandatory
> [u]int_leastN_t: 8 mandatory
> [u]int_fastN_t: 8 mandatory
> [u]intmax_t: 2
> [u]intprt_t: 2
> size_t, ptrdiff_t, wchar_t, char16_t, char32_t
> atomic_ versions of all of the above: total of 37 mandatory.
> sig_atomic_t, wint_t
>
> That's a total of 74 mandatory types that are required to be integers,
> and in principle they could all be distinct types.

can be 10000 the type uintxx_t
but for me is not a problem because i know it is one unsigned of xx bit...




0
io_x
9/13/2012 9:58:11 AM
"James Kuyper" <jameskuyper@verizon.net> wrote in message
news:5050F71F.80902@verizon.net...
> On 09/12/2012 03:36 PM, BartC wrote:

>> (I use 'int' and 'word' for signed/unsigned integers of natural width;
>> int:N
>> and word:N for specific bitwidths, and int*N and byte*N for specific
>> bytewidths; while 'byte' is a synonym for word:8. For value ranges, I use
>
> I strongly recommend against using non-standard definitions for terms
> defined by the C standard such as 'int' and 'byte' in this newsgroup -
> it can only lead to confusion.

That was an example of a different approach (in my own language) to dealing
with families of integer types. But this morning I had better luck in
finding the datatypes used by Go (a modern language with C-style syntax) and
that uses:

 uint8, uint16, uint32, uint64
 int8, int16, int32, int64

While C# uses:

byte, ushort, uint, ulong  of sizes 8, 16, 32, 64
sbyte, short, int, long  of sizes 8, 16, 32, 64

All pretty much corresponding to the 8 integer types that I said were
typical.

So where is size_t and ptr_diff_t amongst that lot? See, it's possible to
manage without it! So C's approach *does* seem untidy.

However, the context in this subthread was whether C was a suitable starting
point for a hypothetical universal language. Since such a language would 
need to incorporate, amongst many other extremes, the type handling of Ada, 
with that of Python, plus all the manipulations allowed by C, then that's 
obviously a non-starter.

-- 
Bartc
 

0
bc (2337)
9/13/2012 10:36:03 AM
"BartC" <bc@freeuk.com> writes:

> "James Kuyper" <jameskuyper@verizon.net> wrote in message
> news:5050F71F.80902@verizon.net...
>> On 09/12/2012 03:36 PM, BartC wrote:
>
>>> (I use 'int' and 'word' for signed/unsigned integers of natural width;
>>> int:N
>>> and word:N for specific bitwidths, and int*N and byte*N for specific
>>> bytewidths; while 'byte' is a synonym for word:8. For value ranges, I use
>>
>> I strongly recommend against using non-standard definitions for terms
>> defined by the C standard such as 'int' and 'byte' in this newsgroup -
>> it can only lead to confusion.
>
> That was an example of a different approach (in my own language) to dealing
> with families of integer types. But this morning I had better luck in
> finding the datatypes used by Go (a modern language with C-style syntax) and
> that uses:
>
> uint8, uint16, uint32, uint64
> int8, int16, int32, int64

Go also has int, uint and uintptr with implementation-defined widths.

> While C# uses:
>
> byte, ushort, uint, ulong  of sizes 8, 16, 32, 64
> sbyte, short, int, long  of sizes 8, 16, 32, 64

(C# has a type char which is also considered to be an integral type.)

> All pretty much corresponding to the 8 integer types that I said were
> typical.
>
> So where is size_t and ptr_diff_t amongst that lot? See, it's possible to
> manage without it! So C's approach *does* seem untidy.

Go has some of these.

<snip>
-- 
Ben.
0
ben.usenet (6790)
9/13/2012 11:03:18 AM
On Sep 12, 3:58=C2=A0pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
wrote:
> =D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=A8=D7=91=D7=
=99=D7=A2=D7=99, 12 =D7=91=D7=A1=D7=A4=D7=98=D7=9E=D7=91=D7=A8 2012 14:31:1=
8 UTC+1, =D7=9E=D7=90=D7=AA Nick Keighley:> On Sep 12, 12:40=C2=A0pm, Malco=
lm McLean <malcolm.mcle...@btinternet.com>

> >> I'd say it needs essentially C syntax - loops, curly brackets, non-flo=
w
> >> control non-arithemtical functionality implemented as functions rather=
 than >> the core language. That's generally been accepted.
>
> > by whom? You seem to saying we need a single low level procedural
> > language. I'm not sure your wish-list is consistent. lets call it
> > Single Procedural Language (SPL)
>
> Most modern new languages go for curly braces and a superfically at least
> C-like syntax.

but considerable differences in semantics

> But there are exceptions, of course. If there were no exceptions
> at all then saying "we need essential C-like syntax" would be as fatuous =
as
> saying "we should standardise on Arabic numerals".

it wasn't the syntax I had a problem with. It was the semantic wish-
list. I suspect C-like syntax isn't the "best possible" syntax but its
well known and widely used. I'm not sure what SPL is for.

0
9/13/2012 11:24:35 AM
On 09/13/2012 06:36 AM, BartC wrote:
> "James Kuyper" <jameskuyper@verizon.net> wrote in message
> news:5050F71F.80902@verizon.net...
>> On 09/12/2012 03:36 PM, BartC wrote:
> 
>>> (I use 'int' and 'word' for signed/unsigned integers of natural width;
>>> int:N
>>> and word:N for specific bitwidths, and int*N and byte*N for specific
>>> bytewidths; while 'byte' is a synonym for word:8. For value ranges, I use
>>
>> I strongly recommend against using non-standard definitions for terms
>> defined by the C standard such as 'int' and 'byte' in this newsgroup -
>> it can only lead to confusion.
> 
> That was an example of a different approach (in my own language) to dealing
> with families of integer types.

I strongly recommend conspicuously labeling all uses of such a different
approach in a C-oriented forum to prevent any possibility of confusion
with C's standard-defined terms that have the same spelling. For
instance, instead of 'int', write something like mylanguage::int.

....
> So where is size_t and ptr_diff_t amongst that lot? See, it's possible to
> manage without it! So C's approach *does* seem untidy.

C90's integer types have sizes that vary from one implementation to
another, which is why a typedef is needed for a type like C99's int32_t,
that has the same size on all platforms (or at least, on all platforms
where there is any supported integer type of that size). The example you
gave appeared to be of languages where the basic types have a fixed
size, which would remove the need for such typedefs. However, by the
same token, that creates the need for other typedefs: one for the
natural int type for a given platform, regardless of what size that type
is - call it natural_int or nint, corresponding to C's built-in 'int'
type (in C99, int_fast16_t is a clumsier representation of roughly the
same idea). Either way, if you have multiple similar types, you
sometimes need to have the type chosen vary with context, and you then
need something like C's typedef to record which of those types was
chosen. And that's where things like size_t and ptrdiff_t come in.

> However, the context in this subthread was whether C was a suitable starting
> point for a hypothetical universal language. Since such a language would 
> need to incorporate, amongst many other extremes, the type handling of Ada, 
> with that of Python, plus all the manipulations allowed by C, then that's 
> obviously a non-starter.

If you're giving those languages as examples because you consider them
to be the best in each of those areas, you're probably aiming too high.
An "everything" language will necessarily involve a lot of compromises;
you'll be lucky if it handles types as well as the average language;
it's not likely to handle them as well as the language (whichever one
that is) that handles types best. The same is likely to be true of every
other desirable feature of the language.
-- 
James Kuyper
0
jameskuyper (5635)
9/13/2012 11:33:49 AM
On Sep 12, 10:18=C2=A0pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
wrote:
> =D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=A8=D7=91=D7=
=99=D7=A2=D7=99, 12 =D7=91=D7=A1=D7=A4=D7=98=D7=9E=D7=91=D7=A8 2012 20:57:1=
0 UTC+1, =D7=9E=D7=90=D7=AA Bart:> "James Kuyper" <jameskuy...@verizon.net>=
 wrote in message
>
> > I thought Malcolm was suggesting the use of a single int type instead o=
f the
> > four common widths supported by many CPUs (plus signed/unsigned variati=
ons).
>
> > Perhaps dealing with all my eight types isn't a big deal after all..
>
> Most data is integers, strings, reals or enums.

chars, bools

> Beyond that level of granularity
> it becomes very domain-specific. There's a tension between the needs of t=
he
> machine and the needs of the data. In a universal computer languge, the l=
ine
> would have to be drawn to empahsise the needs of the data.

0
9/13/2012 12:15:25 PM
On Sep 12, 11:40=A0pm, mike3 <mike4...@yahoo.com> wrote:
> On Sep 1, 10:29=A0pm, "Anse" <blankon...@framebuilder.net> wrote:
>
> > Kaz Kylheku wrote:
> <snip>
> > > Just say no to these clowns.
>
> > Most are actually pretty darned smart. But when they start on their "sp=
iel",
> > I give it right back to them and then some, but they do not seem to be
> > learning from it. I think they see everything as a pissing contest. Hav=
e you
> > ever seen a C or C++ programmer admit that they were wrong or that some=
one
> > else actually has a good point? They see everything as a threat. I gues=
s
> > that is what a focus on sports in schools and fraterneties result in. S=
igh.
> > I think this is why much of the world sees "Americans" as stupid. Which=
, of
> > course, begs the question, "Is USA's largest export, stupidity?".
>
> 1. So does this mean everyone in the entire "rest of the world" is
> "not stupid"
> in this way, and _ONLY_ Americans are?
>
> 2. Are _all_ the C/C++ programmers who refuse to admit they're wrong
> or that
> others' points are good, American?

not all C or C++ programmers are American
0
9/13/2012 12:18:43 PM

"Ben Bacarisse" <ben.usenet@bsb.me.uk> wrote in message
news:0.ab886e10d5b5b755b446.20120913120318BST.87wqzyi3rd.fsf@bsb.me.uk...
> "BartC" <bc@freeuk.com> writes:
>> That was an example of a different approach (in my own language) to
>> dealing
>> with families of integer types. But this morning I had better luck in
>> finding the datatypes used by Go (a modern language with C-style syntax)
>> and
>> that uses:
>>
>> uint8, uint16, uint32, uint64
>> int8, int16, int32, int64
>
> Go also has int, uint and uintptr with implementation-defined widths.

OK, int and uint are described a few lines further down. They are just
integers with default width for that machine (which I suspect will be either
32 or 64 bits).

That's even closer to my approach (no width specified it uses a default,
currently 32 bits).

uintptr will follow from that.

(That could be said to be similar to what C does with it's int and intxx_t,
except that I believe that intxx_t types are defined in terms of ints
(short, long int etc) instead of the other way around.)

-- 
Bartc 

0
bc (2337)
9/13/2012 12:30:36 PM
On Wednesday, September 12, 2012 6:40:25 AM UTC-5, Malcolm McLean wrote:
> =D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=A8=D7=91=D7=
=99=D7=A2=D7=99, 12 =D7=91=D7=A1=D7=A4=D7=98=D7=9E=D7=91=D7=A8 2012 09:01:5=
3 UTC+1, =D7=9E=D7=90=D7=AA Nick Keighley:
>=20
> > On Sep 11, 11:14=C2=A0pm, Malcolm McLean <malcolm.mcle...@btinternet.co=
m>
> >=20
> > oh. I assumed you were proposing Lisp *as* the universal hammer. Which=
=20
> > blub are you proposing then? PL/I was the last attempt.
> >
>=20
> I'd say it needs essentially C syntax - loops, curly brackets, non-flow=
=20
> control non-arithemtical functionality implemented as functions rather=20
> than the core language. That's generally been accepted.
>=20

Haskell seems to do pretty well without loops or curly brackets.

Quicksort in Haskell:

quicksort :: Ord a =3D> [a] -> [a]
quicksort []     =3D []
quicksort (p:xs) =3D (quicksort lesser) ++ [p] ++ (quicksort greater)
    where
        lesser  =3D filter (< p) xs
        greater =3D filter (>=3D p) xs

   =20
Of course, there *is* no universal hammer, because the universe is too=20
goddamned big.  What works really well for OS kernels and device drivers=20
would be painful to use for Web apps, which would in turn be painful to use=
=20
for serious number crunching.
0
jfbode1029 (228)
9/13/2012 8:00:13 PM
"BartC" <bc@freeuk.com> writes:

> "Ben Bacarisse" <ben.usenet@bsb.me.uk> wrote in message
> news:0.ab886e10d5b5b755b446.20120913120318BST.87wqzyi3rd.fsf@bsb.me.uk...
>> "BartC" <bc@freeuk.com> writes:
>>> That was an example of a different approach (in my own language) to
>>> dealing
>>> with families of integer types. But this morning I had better luck in
>>> finding the datatypes used by Go (a modern language with C-style syntax)
>>> and
>>> that uses:
>>>
>>> uint8, uint16, uint32, uint64
>>> int8, int16, int32, int64
>>
>> Go also has int, uint and uintptr with implementation-defined widths.
>
> OK, int and uint are described a few lines further down. They are just
> integers with default width for that machine (which I suspect will be either
> 32 or 64 bits).
>
> That's even closer to my approach (no width specified it uses a default,
> currently 32 bits).
>
> uintptr will follow from that.

I wasn't commenting on your approach (I don't know what that is).  I
thought you were citing Go as an example of a language that did without
implementation-defined integer sizes.

<snip>
-- 
Ben.
0
ben.usenet (6790)
9/13/2012 8:32:34 PM
"BartC" <bc@freeuk.com> writes:
[...]
> That was an example of a different approach (in my own language) to dealing
> with families of integer types. But this morning I had better luck in
> finding the datatypes used by Go (a modern language with C-style syntax) and
> that uses:
>
>  uint8, uint16, uint32, uint64
>  int8, int16, int32, int64
>
> While C# uses:
>
> byte, ushort, uint, ulong  of sizes 8, 16, 32, 64
> sbyte, short, int, long  of sizes 8, 16, 32, 64
>
> All pretty much corresponding to the 8 integer types that I said were
> typical.
>
> So where is size_t and ptr_diff_t amongst that lot? See, it's possible to
> manage without it! So C's approach *does* seem untidy.
[...]

Sure, it's untidy, but IMHO necessary, at least for C.

Having a range of integer types with specified sizes can be
convenient, but they don't eliminate the need for types defined
in terms of how they're used rather than how they're represented.
C's size_t, in particular, has a size defined by the compiler,
not by its size.

There are several possible approaches that can be used in defining
built-in integer types for a language.

You can start with a set of types with exactly specified sizes,
as Go and C# do; you might then define other types in terms of those.

Or you can define a set of types with implementation-defined sizes,
as C has always done; C99 then added the [u]intN_t types that are
defined in an implementation-defined manner in terms of those.

The former approach probably would not have been practical, say,
40 or 50 years ago, because there were existing systems whose
hardware-supported types were multiples of 6, 8, or 9 bits.
That's the environment in which C was developed.

The industry seems to have settled on 8, 16, 32, and 64 bits as the
usual sizes for hardware-supported integers, and 2's-complement
as the representation for signed integers.  The designers of Go
and C# have chosen to build that assumption into their languages.
That probably made good sense, but I wonder how that decision will
look 40 or 50 years from now.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
9/13/2012 9:16:09 PM
"BartC" <bc@freeuk.com> writes:
[...]
> OK, int and uint are described a few lines further down. They are just
> integers with default width for that machine (which I suspect will be either
> 32 or 64 bits).
>
> That's even closer to my approach (no width specified it uses a default,
> currently 32 bits).
>
> uintptr will follow from that.
>
> (That could be said to be similar to what C does with it's int and intxx_t,
> except that I believe that intxx_t types are defined in terms of ints
> (short, long int etc) instead of the other way around.)

The word "int" is not a collective term for the types short, int, and
long.  Yes the word does appear in some forms of the names of the types
(short int, long int), but IMHO it's best *not* to think of "short int"
as a phrase in which "short" modifies "int".  short int, int, and long
int are all *integer* types.

"int" is a single type (also known as "signed int").  "short" and "long"
are distinct types, whichever of their several names you use.

To address your point, the intN_t and uintN_t types are defined
as typedefs, i.e., as aliases for existing types.  In most
implementations, the chosen existing types are predefined types
such as char, short, int, long, or long long, or their signed
or unsigned variants.  They can also be defined as typedefs for
implementation-defined "extended" types, but I don't know of any
compiler that does so.  Types such as short, int, and long are built
into the language, and syntactically, their names are composed of
keywords.  See section 6.2.5 of the C standard for more information
about predefined types.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
    Will write code for food.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
0
kst-u (21963)
9/13/2012 10:13:50 PM
On Sep 13, 12:33=A0pm, James Kuyper <jameskuy...@verizon.net> wrote:
> On 09/13/2012 06:36 AM, BartC wrote:

<snip>

> > However, the context in this subthread was whether C was a suitable sta=
rting
> > point for a hypothetical universal language. Since such a language woul=
d
> > need to incorporate, amongst many other extremes, the type handling of =
Ada,
> > with that of Python, plus all the manipulations allowed by C, then that=
's
> > obviously a non-starter.
>
> If you're giving those languages as examples because you consider them
> to be the best in each of those areas, you're probably aiming too high.
> An "everything" language will necessarily involve a lot of compromises;
> you'll be lucky if it handles types as well as the average language;
> it's not likely to handle them as well as the language (whichever one
> that is) that handles types best. The same is likely to be true of every
> other desirable feature of the language.

which leaves me wondering what purpose this "everything language"
serves
0
9/14/2012 10:35:33 AM
On Sep 13, 1:15=C2=A0pm, Nick Keighley <nick_keighley_nos...@hotmail.com>
wrote:
> On Sep 12, 10:18=C2=A0pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
> wrote:
>
> > =D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=A8=D7=91=D7=
=99=D7=A2=D7=99, 12 =D7=91=D7=A1=D7=A4=D7=98=D7=9E=D7=91=D7=A8 2012 20:57:1=
0 UTC+1, =D7=9E=D7=90=D7=AA Bart:> "James Kuyper" <jameskuy...@verizon.net>=
 wrote in message
>
> > > I thought Malcolm was suggesting the use of a single int type instead=
 of the
> > > four common widths supported by many CPUs (plus signed/unsigned varia=
tions).
>
> > > Perhaps dealing with all my eight types isn't a big deal after all..
>
> > Most data is integers, strings, reals or enums.
>
> chars, bools

functions, monads, continuations..


> > Beyond that level of granularity
> > it becomes very domain-specific. There's a tension between the needs of=
 the
> > machine and the needs of the data. In a universal computer languge, the=
 line
> > would have to be drawn to empahsise the needs of the data.- Hide quoted=
 text -
>
> - Show quoted text -

0
9/14/2012 10:37:30 AM
Nick Keighley <nick_keighley_nospam@hotmail.com> writes:

> On Sep 13, 12:33 pm, James Kuyper <jameskuy...@verizon.net> wrote:
>> On 09/13/2012 06:36 AM, BartC wrote:
>
> <snip>
>
>> > However, the context in this subthread was whether C was a suitable starting
>> > point for a hypothetical universal language. Since such a language would
>> > need to incorporate, amongst many other extremes, the type handling of Ada,
>> > with that of Python, plus all the manipulations allowed by C, then that's
>> > obviously a non-starter.
>>
>> If you're giving those languages as examples because you consider them
>> to be the best in each of those areas, you're probably aiming too high.
>> An "everything" language will necessarily involve a lot of compromises;
>> you'll be lucky if it handles types as well as the average language;
>> it's not likely to handle them as well as the language (whichever one
>> that is) that handles types best. The same is likely to be true of every
>> other desirable feature of the language.
>
> which leaves me wondering what purpose this "everything language"
> serves

Yes, me too.

When I first saw Malcolm's post I thought he was being sarcastic, but it
seems not.

I can understand the remark if it's born of frustration: why do we have
so many similar languages? but not if it born of a desire to fix the
situation with one universal language.

For example, from a technical point of view, having both Java and C# is
daft, but we have both because of the way businesses work.  There is
also a reason to be frustrated when new languages repeat the mistakes of
previous ones.  I hope never to see a new programming language that
thinks a character is a byte, or one that has no high-level concurrency
control, but I am certain I'll be disappointed!

So I can imagine having fewer languages, but the language design space
is too vast to covered by only a few data points.

-- 
Ben.
0
ben.usenet (6790)
9/14/2012 11:21:02 AM

"Nick Keighley" <nick_keighley_nospam@hotmail.com> wrote in message 
news:baabefd7-e5e4-474e-8ff7-83fbf4f0cd9c@gq8g2000vbb.googlegroups.com...
> On Sep 13, 1:15 pm, Nick Keighley <nick_keighley_nos...@hotmail.com>
> wrote:
>> On Sep 12, 10:18 pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
>> wrote:
>>
>> > בתאריך יום רביעי, 12 בספטמבר 2012 20:57:10 UTC+1, מאת Bart:> "James 
>> > Kuyper" <jameskuy...@verizon.net> wrote in message
>>
>> > > I thought Malcolm was suggesting the use of a single int type instead 
>> > > of the
>> > > four common widths supported by many CPUs (plus signed/unsigned 
>> > > variations).
>>
>> > > Perhaps dealing with all my eight types isn't a big deal after all..
>>
>> > Most data is integers, strings, reals or enums.
>>
>> chars, bools
>
> functions, monads, continuations..

He said *most* data. How many everyday programmers are dealing with monads 
(whatever they are) and continuations (whatever *those* are)?

Most data *is* numbers and strings; and even strings are really just 
sequences of numbers.

-- 
Bartc 

0
bc (2337)
9/14/2012 12:58:37 PM
=D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=A9=D7=99=D7=A9=
=D7=99, 14 =D7=91=D7=A1=D7=A4=D7=98=D7=9E=D7=91=D7=A8 2012 14:00:34 UTC+1, =
=D7=9E=D7=90=D7=AA Bart:
> "Nick Keighley" <nick_keighley_nospam@hotmail.com> wrote in message=20
>=20
>=20
> Most data *is* numbers and strings; and even strings are really just =20
> sequences of numbers.
>=20
Data is also ones and zeros. And it's dates, names, x,y,z co-ordinates,=20
employee records.
One question is, what's the level of granularity, and thus generality, at=
=20
which it becomes sensible to have support at the level of the language? But=
=20
the question I'm asking is slightly different. If two programming language
entities represent essentially the same data, can we not eliminate one? Do=
=20
we need double and float? Do we need strings and characters, or can a=20
character be a one-letter string? Do we need twelve or so integer types?

Of course types aren't added for the sake of it, and there are machine=20
efficiency reasons for different types. But it seems to me that the integer=
 types, in particular need rationalisation.
0
9/14/2012 3:18:22 PM
On Friday, September 14, 2012 8:00:34 AM UTC-5, Bart wrote:
> "Nick Keighley" <nick_keighley_nospam@hotmail.com> wrote in message=20
>=20
> news:baabefd7-e5e4-474e-8ff7-83fbf4f0cd9c@gq8g2000vbb.googlegroups.com...
>=20
> > On Sep 13, 1:15 pm, Nick Keighley <nick_keighley_nos...@hotmail.com>
> > wrote:
> >> On Sep 12, 10:18 pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
> >> wrote:
> >>
> >> > =D7=91=D7=AA=D7=90=D7=A8=D7=99=D7=9A =D7=99=D7=95=D7=9D =D7=A8=D7=91=
=D7=99=D7=A2=D7=99, 12 =D7=91=D7=A1=D7=A4=D7=98=D7=9E=D7=91=D7=A8 2012 20:5=
7:10 UTC+1, =D7=9E=D7=90=D7=AA Bart:> "James=20
> >> > Kuyper" <jameskuy...@verizon.net> wrote in message
> >>
> >> > > I thought Malcolm was suggesting the use of a single int type inst=
ead=20
> >> > > of the
> >> > > four common widths supported by many CPUs (plus signed/unsigned=20
> >> > > variations).
> >>
> >> > > Perhaps dealing with all my eight types isn't a big deal after all=
...
> >>
> >> > Most data is integers, strings, reals or enums.
> >>
> >> chars, bools
> >
> > functions, monads, continuations..
>=20
> He said *most* data. How many everyday programmers are dealing with monad=
s=20
> (whatever they are) and continuations (whatever *those* are)?

Anyone doing functional programming in Haskell or a similar language.
Which, while not a huge number, is significant.

If we want to get truly pedantic, all data (at least in the context of
digital computers) is some arrangement of bits in memory.  When you get rig=
ht
down to it, all we work with are bits, bytes, and words (which means BLISS =
is
the ultimate programming language).

Doesn't mean higher-level, abstract types (like functions and monads) aren'=
t=20
useful (even necessary in some domains).
=20
0
jfbode1029 (228)
9/14/2012 3:33:35 PM
Nick Keighley wrote:

> which leaves me wondering what purpose this "everything language"
> serves

Or you won't have you being just a someone putting a part in a car?



0
gbn2012 (24)
9/30/2012 9:31:54 AM
Nick Keighley wrote:
> On Sep 13, 12:33 pm, James Kuyper <jameskuy...@verizon.net> wrote:
>> On 09/13/2012 06:36 AM, BartC wrote:
>
> <snip>
>
>>> However, the context in this subthread was whether C was a suitable
>>> starting point for a hypothetical universal language. Since such a
>>> language would need to incorporate, amongst many other extremes,
>>> the type handling of Ada, with that of Python, plus all the
>>> manipulations allowed by C, then that's obviously a non-starter.
>>
>> If you're giving those languages as examples because you consider
>> them to be the best in each of those areas, you're probably aiming
>> too high. An "everything" language will necessarily involve a lot of
>> compromises; you'll be lucky if it handles types as well as the
>> average language; it's not likely to handle them as well as the
>> language (whichever one that is) that handles types best. The same
>> is likely to be true of every other desirable feature of the
>> language.
>
> which leaves me wondering what purpose this "everything language"
> serves

Do you  want a union? Do you want a leader? 


0
gbn2012 (24)
9/30/2012 9:33:14 AM
Ben Bacarisse wrote:

> I can understand the remark

Not to be obtuse but how about  you shut up a bit? 


0
gbn2012 (24)
9/30/2012 9:35:39 AM
Nick Keighley wrote:

you killed people 


0
gbn2012 (24)
9/30/2012 9:36:33 AM
BartC wrote:

you want to kill people 


0
gbn2012 (24)
9/30/2012 9:37:09 AM
Nick Keighley wrote:

my bad on you, you have killed people 


0
gbn2012 (24)
9/30/2012 9:38:45 AM
Nick Keighley <nick_keighley_nospam@hotmail.com> writes:

> On Sep 13, 1:15 pm, Nick Keighley <nick_keighley_nos...@hotmail.com>
> wrote:
>> On Sep 12, 10:18 pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
>> wrote:
>>
>> >  <<D7>>  <<91>>  <<D7>>  <<AA>>  <<D7>>  <<90>>  <<D7>>  <<A8>>  <<D7>>  <<99>>  <<D7>>  <<9A>>   <<D7>>  <<99>>  <<D7>>  <<95>>  <<D7>>  <<9D>>   <<D7>>  <<A8>>  <<D7>>  <<91>>  <<D7>>  <<99>>  <<D7>>  <<A2>>  <<D7>>  <<99>> , 12  <<D7>>  <<91>>  <<D7>>  <<A1>>  <<D7>>  <<A4>>  <<D7>>  <<98>>  <<D7>>  <<9E>>  <<D7>>  <<91>>  <<D7>>  <<A8>>  2012 20:57:10 UTC+1,  <<D7>>  <<9E>>  <<D7>>  <<90>>  <<D7>>  <<AA>>  Bart:> "James Kuyper" <jameskuy...@verizon.net> wrote in message
>>
>> > > I thought Malcolm was suggesting the use of a single int type instead of the
>> > > four common widths supported by many CPUs (plus signed/unsigned variations).
>>
>> > > Perhaps dealing with all my eight types isn't a big deal after all..
>>
>> > Most data is integers, strings, reals or enums.
>>
>> chars, bools
>
> functions, monads, continuations..

Monads aren't really a datatype, even a generic datatype like
'list' or 'array', but more like a datatype pattern, something like
a function that operates on type constructors (of which 'list' and
'array' are both examples).  That puts them in a different category
(no pun intended) than other datatypes, even generic ones like
lists and arrays.
0
txr1 (1467)
12/17/2012 10:49:20 PM
Tim Rentsch wrote:
> Nick Keighley <nick_keighley_nospam@hotmail.com> writes:
>
>> On Sep 13, 1:15 pm, Nick Keighley <nick_keighley_nos...@hotmail.com>
>> wrote:
>>> On Sep 12, 10:18 pm, Malcolm McLean <malcolm.mcle...@btinternet.com>
>>> wrote:
>>>
>>>>   <<D7>>  <<91>>  <<D7>>  <<AA>>  <<D7>>  <<90>>  <<D7>>  <<A8>>  <<D7>>  <<99>>  <<D7>>  <<9A>>   <<D7>>  <<99>>  <<D7>>  <<95>>  <<D7>>  <<9D>>   <<D7>>  <<A8>>  <<D7>>  <<91>>  <<D7>>  <<99>>  <<D7>>  <<A2>>  <<D7>>  <<99>> , 12  <<D7>>  <<91>>  <<D7>>  <<A1>>  <<D7>>  <<A4>>  <<D7>>  <<98>>  <<D7>>  <<9E>>  <<D7>>  <<91>>  <<D7>>  <<A8>>  2012 20:57:10 UTC+1,  <<D7>>  <<9E>>  <<D7>>  <<90>>  <<D7>>  <<AA>>  Bart:> "James Kuyper" <jameskuy...@verizon.net> wrote in message

:)

-- 
Ian Collins
0
ian-news (10155)
12/17/2012 11:11:19 PM
Reply: