Topic: Improving C and C++ header compatibility


Author: Richard Smith <richard@ex-parrot.com>
Date: Tue, 22 Mar 2011 13:30:11 CST
Raw View
[Resent after 80+ hours.]

It's quite common to want to write a header for a library written in C
that can be used from both C and C++.  Conceptually, this is quite
straightforward, but in practice it usually seems to get needlessly
messy.  I think it would be easy to make a very few minor and safe
changes to C++ that would make this process a lot cleaner.

Let's take a very simple example.  I have a function that acts as
strncpy except that it returns true if it copied up to a null
character on the source string, and false if it stopped because the
the destination buffer was false.  This might have the signature:

  bool my_strncpy( char const* src, char* dst, size_t n );

Let's look at what's needed to turn this into a reasonable quality C/C
+
+ header.  It starts off easily enough:

1)  Include guards.  Easy enough: the same syntax works in both
languages.

2)  Include a header for size_t.  Again, easy enough: the <stddef.h>
header does this in both languages, and avoids any complications that
might (in theory if not in practice) exist with <cstddef> putting it
in the std namespace.

But now things start getting messy:

3)  In C, we need a header for bool.  In principle, this is easy:
<stdbool.h> does the right thing in C and is (nearly) a no-op in C++.
But in practice, it's bad practice to include <stdbool.h> from a
library header in C.  It's not uncommon to find programs originally
written for C90 that have defined true, false and (more troublesomely)
bool as integers.  The macros in <stdbool.h> would break that.  The
boolean keyword in C99 is spelt _Bool, and it's good practice to use
this instead of the bool macro in a C header.  We're not allowed to
define _Bool as a macro in C++ as it's a reserve word, so we're left
either doing something like:

  #if __cplusplus
  #define MYLIBRARY_BOOL bool
  #else
  #define MYLIBRARY_BOOL _Bool
  #endif

4)  In C, the restrict keyword (might) allow the compiler to make
better more assumptions about the two arguments and therefore optimise
it better; it also potentially allows for a compiler warning if the
same argument is supplied for both parameters.  So far as I'm
concerned, the jury's still out as to whether this really does make a
significant improvement, but it's reasonable to assume a library
author might want to add it to the function.  This means adding
another MYLIBRARY_RESTRICT macro as restrict is not permitted in C++.

5)  We need to wrap the declaration in an extern "C" block that's only
compiled in C++, or alternatively put extern "C" before each
declaration in the header.

6)  Finally, we may need some platform-specific code to make shared
libraries work, for example, on Window's we're likely to want to place
__declspec(dllimport) before each declaration in the header.  This
needs wrapping in a macros, say MYLIBRARY_API, so that it's only used
in the appropriate places.

I've just implemented all of that for my single function library and
my header is now has 32 non-empty lines, of which 27 are preprocessing
directives.  In a real library, I'd have rather more declarations and
so the content-to-noise ratio improves a bit; I may also choose to
split the MYLIBRARY_BOOL, RESTRICT and API macros into their own
"mylibrary/config.h" so they can be reused.  But none of that changes
the fact that these hoops need jumping through.  Nor does it change
the fact that my declaration is now covered in macros:

  MYLIBRARY_API MYLIBRARY_BOOL
  my_strncpy( char const* MYLIBRARY_RESTRICT src,
              char* MYLIBRARY_RESTRICT dst, size_t n );

In my experience, some (many, even) C library authors don't especially
care about C++.  Sometimes, avoiding naming their function parameters
'new' or 'class' is about as far as they're willing to go in the name
of C / C++ compatibility.  If they happen to need a MYLIBRARY_BOOL
macro to ensure C90 compatibility, they'll probably use it to ensure C
+
+ compatibility too, but if (when) C90 compatibility is not relevant,
they'll just stick to _Bool as, let's face it, those macros hardly
improve the code's readability.

I think that with three minor additions to the C++ language, we could
significantly improve C / C++ compatibility and make these things a
lot easier.  (Additions A & B are the important ones.)

A)  Make _Bool an alternative token for bool.  So far as I can see,
this is as simple as adding it to the table of alternative tokens in
2.6 [lex.digraph], and to the table of alternative representations in
2.12 [lex.key].  I don't think any actual text is required.  As a
(less good) alternative, the C++ standard good mandate that _Bool is
defined as a macro in <stddef.h> -- that header on the basis that it
is the lightest-weight and most included header there is.  (Although
<stdbool.h> might seem a better choice, it isn't.  The situation when
_Bool is used is precisely the situation in which <stdbool.h> is not
included.  Having it additionally defined in <stdbool.h> might be
acceptable, though.)

B)  Introduce restrict as a C++ keyword, but with no meaning.  I think
most people would accept that using 'restrict' as an identifier in a C
+
+ program is now bad practice.  Presumably when the C standards
committee were drafting C99 they did research and came to the
conclusion that it was only rarely used as an identifier in existing
code, else they would have named the keyword something else (e.g.
_Restrict).  It seems fair to assume the same is true in C++.  In
addition to listing it in the table of keywords in 2.12 [lex.key],
some text would need to be written for 7.1.6.1 [dcl.type.cv].  This
could be as simple as editing the first paragraph to say that restrict
was always redundant (are therefore ignored), and adding a non-
normative footnote saying it is intended to be used for compatibility
with C.

C)  Add a non-normative note paragraph to 7.5 [dcl.link] encouraging
vendors that support other linkage-like options, such as
__declspec(dllimport), to extend the compound linkage specification
grammar to allow them on the extern "Lang" blocks, e.g. extern
__declspec(dllimport) "C" { ... }.  There's precedent for giving
guidance such as this in the standard, for example in
[lib.iterator.traits] guidance on __far pointers is given.

Putting these three minor changes together means that a C/C++ library
header can now contain clean declarations such as:

  _Bool my_strncpy( char const* restrict src, char* restrict dst,
size_t n );

That's far more readable than the earlier version with lots of macros
scattered about.  As a result, it ought to result in C libraries
remaining compatible with C++ as their authors gradually adopt C99
features such as _Bool and restrict are gradually adopted.

Any thoughts?  The changes are all minimal and unlikely to break
anything.  It's too late now for C++0x, sadly,  but they certainly
seem worth considering for the next version (or a TR if there's an
appropriate one).

--
Richard Smith


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: dag@transit.us.cray.com (David A. Greene)
Date: Wed, 23 Mar 2011 13:09:35 CST
Raw View
Richard Smith <richard@ex-parrot.com> writes:

> 4)  In C, the restrict keyword (might) allow the compiler to make
> better more assumptions about the two arguments and therefore optimise
> it better; it also potentially allows for a compiler warning if the
> same argument is supplied for both parameters.  So far as I'm
> concerned, the jury's still out as to whether this really does make a
> significant improvement

It is?  restrict allows parallelization where it otherwise would not
be possible.  This is steadily becoming more important as clock rates
stagnate and core counts increase.

We really need something like restrict in C++.  The semantics of C's
restrict are a bit funky so some tweaking should be done but we
absolutely do want to express the kinds of (non-)aliasing relationships
restrict provides.

                            -Dave


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Joshua Maurice <joshuamaurice@gmail.com>
Date: Wed, 23 Mar 2011 13:08:33 CST
Raw View
On Mar 22, 12:30 pm, Richard Smith <rich...@ex-parrot.com> wrote:
> C)  Add a non-normative note paragraph to 7.5 [dcl.link] encouraging
> vendors that support other linkage-like options, such as
> __declspec(dllimport), to extend the compound linkage specification
> grammar to allow them on the extern "Lang" blocks, e.g. extern
> __declspec(dllimport) "C" { ... }.  There's precedent for giving
> guidance such as this in the standard, for example in
> [lib.iterator.traits] guidance on __far pointers is given.

Brilliant idea.

I would be very much in favor of this alone, with or without the rest.
This would be incredibly useful. I can leave out all of those
obnoxious declspec macros of each function definition, and just have a
couple of lines at the top and bottom of the file to deal with the
windows-isms of shared objects. This is has great value even for pure C
++ code apart from any C-C++ interoperability.

I suspect this is just another thing relegated to this nebulous
"module" support, but this would provide great benefit /now/. Hell,
this should be sent to Microsoft directly for inclusion in their next
compiler. Anyone from Microsoft reading this? Please also include
stuff like calling conventions like thiscall and __cdecl too in the
extern "C" block declaration structure. Would make writing DLL headers
so much more sane.


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Richard Smith <richard@ex-parrot.com>
Date: Wed, 23 Mar 2011 17:54:09 CST
Raw View
On Mar 23, 7:09 pm, d...@transit.us.cray.com (David A. Greene) wrote:
> Richard Smith <rich...@ex-parrot.com> writes:

> > So far as I'm concerned, the jury's still out as to whether this
> > [restrict] really does make a significant improvement
>
> It is?  restrict allows parallelization where it otherwise would not
> be possible.  This is steadily becoming more important as clock rates
> stagnate and core counts increase.

OK.  Perhaps it would be more accurate to say in the sort of C
applications I write, on the operating systems and architectures I'm
familiar with, using the compilers I've bothered investigating, it
doesn't appear to do anything much.  But it's a long time since I've
been a C programmer (rather than a C++ programmer who occasionally
writes C) and I perhaps don't have the breadth of recent experience to
comment sensibly.  In any case, something along the lines of restrict
does seem like it might have the potential to help compilers optimise
code.  And I do tend to sprinkle 'restrict' around my function
declarations in C, even though I'm not certain it's much of a benefit.

By the time we're thinking about C++1x (or 2x, or whatever the version
after C++0x is), I expect we'll know whether restrict has been a
success in C, and if not (or only partially), how it can be improved.
But the idea of adding 'restrict' as a meaningless keyword that can be
placed wherever cv-quals are currently permitted doesn't require us to
think about that, but it's still useful for C / C++ compatibility.
Perhaps instead of saying that restrict has no effect, it could be
left implementation defined with a non-normative note saying that the
intention is for it to be used in a manner compatible with C.  That
would encourage C++ compiler vendors to implement restrict in C++,
which means that if/when the C++1x/2x standard comes to look at
standardising its semantics, they'll actually have experience of how
it might interact with C++'s features which would hopefully reduce the
chance of standardising something suboptimal.

Richard Smith


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Ian Collins <ian-news@hotmail.com>
Date: Tue, 29 Mar 2011 13:07:33 CST
Raw View
On 03/23/11 08:30 AM, Richard Smith wrote:

>
> [Resent after 80+ hours.]
>
> It's quite common to want to write a header for a library written in C
> that can be used from both C and C++.  Conceptually, this is quite
> straightforward, but in practice it usually seems to get needlessly
> messy.  I think it would be easy to make a very few minor and safe
> changes to C++ that would make this process a lot cleaner.
>
> Let's take a very simple example.  I have a function that acts as
> strncpy except that it returns true if it copied up to a null
> character on the source string, and false if it stopped because the
> the destination buffer was false.  This might have the signature:
>
>   bool my_strncpy( char const* src, char* dst, size_t n );
>
> Let's look at what's needed to turn this into a reasonable quality C/C
> +
> + header.  It starts off easily enough:
>
> 1)  Include guards.  Easy enough: the same syntax works in both
> languages.
>
> 2)  Include a header for size_t.  Again, easy enough: the<stddef.h>
> header does this in both languages, and avoids any complications that
> might (in theory if not in practice) exist with<cstddef>  putting it
> in the std namespace.
>
> But now things start getting messy:
>
> 3)  In C, we need a header for bool.  In principle, this is easy:
> <stdbool.h>  does the right thing in C and is (nearly) a no-op in C++.
> But in practice, it's bad practice to include<stdbool.h>  from a
> library header in C.  It's not uncommon to find programs originally
> written for C90 that have defined true, false and (more troublesomely)
> bool as integers.  The macros in<stdbool.h>  would break that.  The
> boolean keyword in C99 is spelt _Bool, and it's good practice to use
> this instead of the bool macro in a C header.  We're not allowed to
> define _Bool as a macro in C++ as it's a reserve word, so we're left
> either doing something like:
>
>   #if __cplusplus
>   #define MYLIBRARY_BOOL bool
>   #else
>   #define MYLIBRARY_BOOL _Bool
>   #endif
>

Is there a compatibility guarantee between C's _Bool and C++'s bool?  I
prefer to play save and use an int return from shared functions.

4)  In C, the restrict keyword (might) allow the compiler to make
> better more assumptions about the two arguments and therefore optimise
> it better; it also potentially allows for a compiler warning if the
> same argument is supplied for both parameters.  So far as I'm
> concerned, the jury's still out as to whether this really does make a
> significant improvement, but it's reasonable to assume a library
> author might want to add it to the function.  This means adding
> another MYLIBRARY_RESTRICT macro as restrict is not permitted in C++.
>

You shouldn't have to do this.  Your environment should take care of this
for you.  Consider the system and C standard libraries which use restrict.

6)  Finally, we may need some platform-specific code to make shared
> libraries work, for example, on Window's we're likely to want to place
> __declspec(dllimport) before each declaration in the header.  This
> needs wrapping in a macros, say MYLIBRARY_API, so that it's only used
> in the appropriate places.
>

This isn't a general problem (it certainly isn't on Unix and Unix like
systems).

Any thoughts?  The changes are all minimal and unlikely to break
> anything.  It's too late now for C++0x, sadly,  but they certainly
> seem worth considering for the next version (or a TR if there's an
> appropriate one).
>

The only real language smell is boolean compatibility and declaration.
Assuming _Bool and bool are compatible, this really boils down to the C
problem of mixing C99 and C95 code.

--
Ian Collins


[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Richard Smith <richard@ex-parrot.com>
Date: Sat, 2 Apr 2011 09:24:36 CST
Raw View
[Again, my first reply to this hasn't reached the newsgroup.]

On Mar 29, 8:07 pm, Ian Collins <ian-n...@hotmail.com> wrote:

> >   #if __cplusplus
> >   #define MYLIBRARY_BOOL bool
> >   #else
> >   #define MYLIBRARY_BOOL _Bool
> >   #endif
>
> Is there a compatibility guarantee between C's _Bool and C++'s bool?  I
> prefer to play save and use an int return from shared functions.

That's an interesting question.

So far as I can see, there's no guarantee that C's _Bool and C++'s
bool are the same.  But, so far as I can see, nor is there a guarantee
that C's short and C++'s short are the same.  For all the other built-
in types, there are standard C library functions that take those types
as arguments, and the guarantee that the C library is callable from C+
+ effectively guarantees that the types are compatible in C and C++.
At present, the C library does not contain any functions that use
_Bool or short so that implicit guarantee doesn't exist for those
types.  (The printf functions with, say, "%hd" pass the short down an
ellipsis which results in integer promotion so that doesn't count.)

That said, I'm really struggling to see why an implementation might
have incompatible boolean types for C and for C++.  For example, I'm
not aware of any requirements imposed by either language that might
require stronger alignment or padding guarantees in one language
compared to the other.

And it seems clear that the C standard committee intended them to be
compatible, otherwise C99 wouldn't have provided the macro called
'bool', when it could easily have called it something else, such as
'boolean'.  Likewise the C++ standard committee seems unlikely to have
adopted <cstdbool> in C++0x if it had intended there to be a
possibility of the types being incompatible.  Finally, if C1x is
published with a <stdatomic.h> containing an atomic_is_lock_free
generic function that returns _Bool (as the current draft does) which
is semantically identical to C++0x's <atomic> function template of the
same name, and if a future C++ standard (or TR) includes C1x's
<stdatomic.h> by reference into the C++ standard library, then that
will implicitly guarantee that the types are compatible.

So I think that for all practical purposes they can be assumed to be
compatible.

> 4)  In C, the restrict keyword (might) allow the compiler to make
>
> > better more assumptions about the two arguments and therefore optimise
> > it better; it also potentially allows for a compiler warning if the
> > same argument is supplied for both parameters.  So far as I'm
> > concerned, the jury's still out as to whether this really does make a
> > significant improvement, but it's reasonable to assume a library
> > author might want to add it to the function.  This means adding
> > another MYLIBRARY_RESTRICT macro as restrict is not permitted in C++.
>
> You shouldn't have to do this.  Your environment should take care of this
> for you.  Consider the system and C standard libraries which use restrict.

I'm not sure I understand what you're saying.  Consider the following
header:

   #ifndef FOO_INCLUDED
   #define FOO_INCLUDED
   void foo( char const* restrict, ... );
   #endif

This could be a C99 header which uses 'restrict' as a keyword, or a C+
+ (or C90) header which uses 'restrict' as a parameter name.  How does
the compiler know which is intended?  Off the top of my head, I'm not
aware of any compilers that support a mechanism (say a #pragma) that
tells the compiler what language (or dialect) the file is written in;
even if such a mechanism does exist in a particular compiler, it's
certainly not general practice to use it.  Nor does the the name of
the file give a clue as to the language, as it's fairly common
practice to use filenames like "foo.h" for both languages.  So, no, I
cannot see how this is can generally be taken care of by my
development environment.

> 6)  Finally, we may need some platform-specific code to make shared
>
> > libraries work, for example, on Window's we're likely to want to place
> > __declspec(dllimport) before each declaration in the header.  This
> > needs wrapping in a macros, say MYLIBRARY_API, so that it's only used
> > in the appropriate places.
>
> This isn't a general problem (it certainly isn't on Unix and Unix like
> systems).

So?

It may only be a minority of systems that require such things, but the
Windows DLL model is an important special case.  If I'm developing a
library, I will often want it to run on as many different systems as
possible, and that will very often include Windows, and frequently in
Windows built as a DLL.  Take a look at the Boost headers for
libraries such as Interprocess, Graph, Thread or Signals, or the
libxml2 or Xerces headers, or the QT graphics libraries or the Curl
library, or any of dozens of others.  They all do it.  Try grepping
through /usr/include on a typical Unix box.  You may be surprised at
how common it is.

But it means that any good, portable library, whether written in C or C
++, needs to put declarations like __declspec(dllimport) on every non-
inline function.  Unlike extern "C" which can be put once at the
beginning of the file and then forgotten, the same does not apply with
__declspec(dllimport), and so you need an otherwise-unnecessary macro
on every single function declaration.


> > Any thoughts?  The changes are all minimal and unlikely to break
> > anything.  It's too late now for C++0x, sadly,  but they certainly
> > seem worth considering for the next version (or a TR if there's an
> > appropriate one).
>
> The only real language smell is boolean compatibility and declaration.
> Assuming _Bool and bool are compatible, this really boils down to the C
> problem of mixing C99 and C95 code.

No.  It's completely different.  Mixing C99 with earlier versions of C
is a temporary problem.  At some point you decide to abandon support
for earlier versions of C.  At the moment, it may still makes sense to
assume that not all compilers support _Bool, in which case a
MYLIBRARY_BOOL macro that expands to either _Bool or int makes sense.
But once the library authors decide they no longer care about pre-C99
compilers, the MYLIBRARY_BOOL macro no longer has a use in C.  And in
my experience, C programmers are *far* more likely to care about
supporting old dialects of C than they are to support C++.  So once
MYLIBRARY_BOOL no longer has a use for C compatibility, it will
frequently vanish, breaking C++; the same applies to
MYLIBRARY_RESTRICT.

By contrast, the problem of compatibility between C and C++ will not
go away.  One of C++'s biggest strengths is that it just use C
libraries without additional effort.  I can't see how it is possibly
in C++'s interests to lose that compatibility, so it's important that C
++ continues to co-evolve with C so that almost all C headers continue
to just work in C++.

Richard Smith


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Francis Glassborow <francis.glassborow@btinternet.com>
Date: Sun, 3 Apr 2011 09:28:39 CST
Raw View
On 02/04/2011 16:24, Richard Smith wrote:
>
> [Again, my first reply to this hasn't reached the newsgroup.]
>
> On Mar 29, 8:07 pm, Ian Collins<ian-n...@hotmail.com>  wrote:
>
>>>   #if __cplusplus
>>>   #define MYLIBRARY_BOOL bool
>>>   #else
>>>   #define MYLIBRARY_BOOL _Bool
>>>   #endif
>>
>> Is there a compatibility guarantee between C's _Bool and C++'s bool?  I
>> prefer to play save and use an int return from shared functions.
>
> That's an interesting question.
>
> So far as I can see, there's no guarantee that C's _Bool and C++'s
> bool are the same.  But, so far as I can see, nor is there a guarantee
> that C's short and C++'s short are the same.  For all the other built-
> in types, there are standard C library functions that take those types
> as arguments, and the guarantee that the C library is callable from C+
> + effectively guarantees that the types are compatible in C and C++.

I am not sure that is true. There is nothing to prevent an implementer
from providing entirely different sizes for built in types in a C and
a C++ implementation. That means that there is no requirement that a C
library compiled with a C compiler can be linked with C++ code
compiled by any C++ compiler.

All that C compatibility requires is that C code compiled with your
C++ compiler will have the same semantics as that code compiled with a
C compiler. However note that implementation defined behaviour reduces
even that guarantee.

Of course individual implementers do not usually introduce problems
with linking code compiled with their C compiler to code compiled with
their C++ compiler but that is only because their customers tend to
scream.

Note that if you were thinking about coming to the ACCU conference
2011 you are too late because it sold out earlier this week. Next year
do not prevaricate and be disappointed. :)

Francis


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Ian Collins <ian-news@hotmail.com>
Date: Thu, 7 Apr 2011 01:29:41 CST
Raw View
On 04/ 3/11 03:24 AM, Richard Smith wrote:
>
> [Again, my first reply to this hasn't reached the newsgroup.]
>
> On Mar 29, 8:07 pm, Ian Collins<ian-n...@hotmail.com>  wrote:

Francis address the first point.

>> 4)  In C, the restrict keyword (might) allow the compiler to make
>>
>>> better more assumptions about the two arguments and therefore optimise
>>> it better; it also potentially allows for a compiler warning if the
>>> same argument is supplied for both parameters.  So far as I'm
>>> concerned, the jury's still out as to whether this really does make a
>>> significant improvement, but it's reasonable to assume a library
>>> author might want to add it to the function.  This means adding
>>> another MYLIBRARY_RESTRICT macro as restrict is not permitted in C++.
>>
>> You shouldn't have to do this.  Your environment should take care of this
>> for you.  Consider the system and C standard libraries which use restrict.
>
> I'm not sure I understand what you're saying.  Consider the following
> header:

What I'm saying is I misunderstood your point!  Checking my system
(Solaris) headers, they have

#if (defined(__STDC__) && defined(_STDC_C99))
#define _RESTRICT_KYWD  restrict
#else
#define _RESTRICT_KYWD
#endif

Which is similar to what you proposed.

>> 6)  Finally, we may need some platform-specific code to make shared
>>
>>> libraries work, for example, on Window's we're likely to want to place
>>> __declspec(dllimport) before each declaration in the header.  This
>>> needs wrapping in a macros, say MYLIBRARY_API, so that it's only used
>>> in the appropriate places.
>>
>> This isn't a general problem (it certainly isn't on Unix and Unix like
>> systems).
>
> So?
>
> It may only be a minority of systems that require such things, but the
> Windows DLL model is an important special case.

May be, but special cases are not something that is standardised.

>>> Any thoughts?  The changes are all minimal and unlikely to break
>>> anything.  It's too late now for C++0x, sadly,  but they certainly
>>> seem worth considering for the next version (or a TR if there's an
>>> appropriate one).
>>
>> The only real language smell is boolean compatibility and declaration.
>> Assuming _Bool and bool are compatible, this really boils down to the C
>> problem of mixing C99 and C95 code.
>
> No.  It's completely different.  Mixing C99 with earlier versions of C
> is a temporary problem.  At some point you decide to abandon support
> for earlier versions of C.  At the moment, it may still makes sense to
> assume that not all compilers support _Bool, in which case a
> MYLIBRARY_BOOL macro that expands to either _Bool or int makes sense.
> But once the library authors decide they no longer care about pre-C99
> compilers, the MYLIBRARY_BOOL macro no longer has a use in C.  And in
> my experience, C programmers are *far* more likely to care about
> supporting old dialects of C than they are to support C++.  So once
> MYLIBRARY_BOOL no longer has a use for C compatibility, it will
> frequently vanish, breaking C++; the same applies to
> MYLIBRARY_RESTRICT.

But surly these are issues for the operating system implementers, not
the language standard?

--
Ian Collins


[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Richard Smith <richard@ex-parrot.com>
Date: Sat, 9 Apr 2011 01:25:46 CST
Raw View
On Apr 7, 8:29 am, Ian Collins <ian-n...@hotmail.com> wrote:
> On 04/ 3/11 03:24 AM, Richard Smith wrote:
>
> > On Mar 29, 8:07 pm, Ian Collins<ian-n...@hotmail.com>  wrote:
>
> Francis address the first point.

He certainly raised some interesting points, but he didn't address my
basic point which was that _Bool should be a C++ keyword.  C and C++
cope sharing the name 'int' between them, despite their not being a
formal guarantee that the types are the same.


> >>> [...]  This means adding
> >>> another MYLIBRARY_RESTRICT macro as restrict is not permitted in C++.
>
> >> You shouldn't have to do this.  Your environment should take care of this
> >> for you.  Consider the system and C standard libraries which use restrict.
>
> > I'm not sure I understand what you're saying.  Consider the following
> > header:
>
> What I'm saying is I misunderstood your point!  Checking my system
> (Solaris) headers, they have
>
> #if (defined(__STDC__) && defined(_STDC_C99))
> #define _RESTRICT_KYWD  restrict
> #else
> #define _RESTRICT_KYWD
> #endif
>
> Which is similar to what you proposed.

And the system headers on the machine I'm using to type this define
__restrict for this purpose.  But that's not standardised so it's of
no help.  I don't care what the system headers do internally as
there's rarely any reason for me to read them.

I do, however, care that whether possible to easily write C library
headers that work as C++.  These macros are no use for that.  Sure, if
I *only* want to compile on Solaris, I can use _RESTRICT_KYWD.
(Though do they document the feature and guarantee that the next
update won't alter it's spelling?).  But that's absolutely no use in
writing portable library headers.  Once again, we're back to requiring
a MYLIBRARY_RESTRICT macro, and experience suggests that library
authors will only use macros that uglify their code if they serves an
important purpose.  To many C programmers, C++ compatibility is not
that important.  But nevertheless, C++ programmers rely fairly heavily
on the fact that C library headers do just work in C++.  The
divergence of C and C++ due to _Bool and restrict will start to hamper
that goal.


> >> 6)  Finally, we may need some platform-specific code to make shared
>
> >>> libraries work, for example, on Window's we're likely to want to place
> >>> __declspec(dllimport) before each declaration in the header.  This
> >>> needs wrapping in a macros, say MYLIBRARY_API, so that it's only used
> >>> in the appropriate places.
>
> >> This isn't a general problem (it certainly isn't on Unix and Unix like
> >> systems).
>
> > So?
>
> > It may only be a minority of systems that require such things, but the
> > Windows DLL model is an important special case.
>
> May be, but special cases are not something that is standardised.

With respect, I think you perhaps need to re-read what I proposed as I
*didn't* propose that __declspec((dllimport)) is standardised.  What I
said was:

|| C)  Add a non-normative note paragraph to 7.5 [dcl.link]
encouraging
|| vendors that support other linkage-like options, such as
|| __declspec(dllimport), to extend the compound linkage specification
|| grammar to allow them on the extern "Lang" blocks, e.g. extern
|| __declspec(dllimport) "C" { ... }.  There's precedent for giving
|| guidance such as this in the standard, for example in
|| [lib.iterator.traits] guidance on __far pointers is given.

That's not standardising anything.  It is encouraging implementers to
adopt a common and less verbose strategy to providing extensions of
this nature.  In fact, thinking further, a better approach might be to
allow an attribute-specifier-seq on the the extern "LANG" block, e.g.:

 extern "C++" [[__declspec(dllimport)]] { ... }

And in that case, it would involve a minor change to the grammar.  But
either way, the important points are (i) that nothing specific to the
Windows DLL model would be standardised, (ii) the syntax is much less
verbose than needed at present because one attribute applies to
multiple functions, (iii) DLL importing and calling convention
overrides (think __cdecl) are the most common example of this, and an
(non-normative) example using one or both of those should be given.


> > No.  It's completely different.  Mixing C99 with earlier versions of C
> > is a temporary problem.  At some point you decide to abandon support
> > for earlier versions of C.  At the moment, it may still makes sense to
> > assume that not all compilers support _Bool, in which case a
> > MYLIBRARY_BOOL macro that expands to either _Bool or int makes sense.
> > But once the library authors decide they no longer care about pre-C99
> > compilers, the MYLIBRARY_BOOL macro no longer has a use in C.  And in
> > my experience, C programmers are *far* more likely to care about
> > supporting old dialects of C than they are to support C++.  So once
> > MYLIBRARY_BOOL no longer has a use for C compatibility, it will
> > frequently vanish, breaking C++; the same applies to
> > MYLIBRARY_RESTRICT.
>
> But surly these are issues for the operating system implementers, not
> the language standard?

*No*.  Pushing the onus of accommodating this to the system
implementers is worse than useless, as it's virtually guaranteed that
different compilers / standard libraries / operating systems will do
it differently.  If one compiler supports a __restrict keyword in C++,
does that actually help me?  Not much, as I still need to wrap that up
in a macro because a second compiler might spell that _RESTRICT_KYWD,
or something else.

The whole point of my email was in making it easy to write clean,
portable C/C++ code.  That was possible in C90/C++98, but the failure
of C++ to support some of the new constructs in C99 is hampering
that.  (And I'm not talking about more specialised constructs such as
_Complex, although fixing to be fully interchangeable with
std::complex<> would be nice; nor am I talking about VLAs, as such
things rarely occur in headers.)

I don't subscribe to be view that macros are evil and must be avoided,
but frequent use of them rapidly makes code hard to understand.  But
equally, if the common subset of the languages supported by the
compilers you care about doesn't include the functionality you want,
macros are essential to ensure portability.  Which leads to a choice:
either you can write portable C/C++ code or you can write clean C/C++
code.  The fact that the standards force you to that choice, even for
a construct as simple as a boolean type, seems to me to be
fundamentally misguided.

Richard Smith


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Francis Glassborow <francis.glassborow@btinternet.com>
Date: Sat, 9 Apr 2011 10:17:25 CST
Raw View
On 09/04/2011 08:25, Richard Smith wrote:
>
> On Apr 7, 8:29 am, Ian Collins<ian-n...@hotmail.com>  wrote:
>> On 04/ 3/11 03:24 AM, Richard Smith wrote:
>>
>>> On Mar 29, 8:07 pm, Ian Collins<ian-n...@hotmail.com>   wrote:
>>
>> Francis address the first point.
>
> He certainly raised some interesting points, but he didn't address my
> basic point which was that _Bool should be a C++ keyword.

Why? A macro fixes any problem there might be.
   C and C++
> cope sharing the name 'int' between them, despite their not being a
> formal guarantee that the types are the same.
>
>
>>>>> [...]  This means adding
>>>>> another MYLIBRARY_RESTRICT macro as restrict is not permitted in C++.

WG21 did not leave out restrict through lack of thought. It was a
consensus opinion that restrict does not deliver and that if it were in
the language it would be defined as doing nothing. If the languages are
going to be incompatible why should we hide it by including a
meaningless keyword?

>>
>>>> You shouldn't have to do this.  Your environment should take care of this
>>>> for you.  Consider the system and C standard libraries which use restrict.

Sure, YOUR ENVIRONMENT not the C++ Standard.

>>
>>> I'm not sure I understand what you're saying.  Consider the following
>>> header:
>>
>> What I'm saying is I misunderstood your point!  Checking my system
>> (Solaris) headers, they have
>>
>> #if (defined(__STDC__)&&  defined(_STDC_C99))
>> #define _RESTRICT_KYWD  restrict
>> #else
>> #define _RESTRICT_KYWD
>> #endif
>>
>> Which is similar to what you proposed.
>
> And the system headers on the machine I'm using to type this define
> __restrict for this purpose.  But that's not standardised so it's of
> no help.  I don't care what the system headers do internally as
> there's rarely any reason for me to read them.
>
> I do, however, care that whether possible to easily write C library
> headers that work as C++.  These macros are no use for that.  Sure, if
> I *only* want to compile on Solaris, I can use _RESTRICT_KYWD.

What exactly is wrong with
#define restrict

In a C++ implementation? It would be wrong in C because you should not
be ~defining a keyword, but fine in C++ where it isn't a keyword.
> (Though do they document the feature and guarantee that the next
> update won't alter it's spelling?).  But that's absolutely no use in
> writing portable library headers.  Once again, we're back to requiring
> a MYLIBRARY_RESTRICT macro, and experience suggests that library
> authors will only use macros that uglify their code if they serves an
> important purpose.  To many C programmers, C++ compatibility is not
> that important.  But nevertheless, C++ programmers rely fairly heavily
> on the fact that C library headers do just work in C++.  The
> divergence of C and C++ due to _Bool and restrict will start to hamper
> that goal.

C made the decision to have _Bool AFTER C++ had had bool for over 5
years for reasons related to legacy code. How sure are you that making
_Bool a keyword in C++ will not break any C++ code?

restrict is a different issue. Where both languages have the same
keyword it should do the same thing (and with the fundamental types that
is true though both languages allow implementation defined sizes). User
defined types (struct and enum, and in C++ class) have some subtle
differences. BTW why not yell at C for not making class a keyword.
Compatibility isn't a one way street and getting as close as we have has
been hard work and involved many hours of thought and discussion led by
a group of people who are well familiar with both languages and have a
real interest in compatibility.

>
>
>>>> 6)  Finally, we may need some platform-specific code to make shared
>>
>>>>> libraries work, for example, on Window's we're likely to want to place
>>>>> __declspec(dllimport) before each declaration in the header.  This
>>>>> needs wrapping in a macros, say MYLIBRARY_API, so that it's only used
>>>>> in the appropriate places.
>>
>>>> This isn't a general problem (it certainly isn't on Unix and Unix like
>>>> systems).
>>
>>> So?
>>
>>> It may only be a minority of systems that require such things, but the
>>> Windows DLL model is an important special case.
>>
>> May be, but special cases are not something that is standardised.
>
> With respect, I think you perhaps need to re-read what I proposed as I
> *didn't* propose that __declspec((dllimport)) is standardised.  What I
> said was:
>
> || C)  Add a non-normative note paragraph to 7.5 [dcl.link]
> encouraging
> || vendors that support other linkage-like options, such as
> || __declspec(dllimport), to extend the compound linkage specification
> || grammar to allow them on the extern "Lang" blocks, e.g. extern
> || __declspec(dllimport) "C" { ... }.  There's precedent for giving
> || guidance such as this in the standard, for example in
> || [lib.iterator.traits] guidance on __far pointers is given.
>
> That's not standardising anything.  It is encouraging implementers to
> adopt a common and less verbose strategy to providing extensions of
> this nature.  In fact, thinking further, a better approach might be to
> allow an attribute-specifier-seq on the the extern "LANG" block, e.g.:
>
>   extern "C++" [[__declspec(dllimport)]] { ... }
>
> And in that case, it would involve a minor change to the grammar.  But
> either way, the important points are (i) that nothing specific to the
> Windows DLL model would be standardised, (ii) the syntax is much less
> verbose than needed at present because one attribute applies to
> multiple functions, (iii) DLL importing and calling convention
> overrides (think __cdecl) are the most common example of this, and an
> (non-normative) example using one or both of those should be given.

I am not sure where you are going on this issue. There is a deep and
fundamental difference between Windows and Unix with dynamic libraries.
A group of very experienced people spent time looking at this to see if
there was any way that C++ could support both as part of the Standard.
Other issues became more pressing so it was abandoned
>
>
>>> No.  It's completely different.  Mixing C99 with earlier versions of C
>>> is a temporary problem.  At some point you decide to abandon support
>>> for earlier versions of C.

FOFL are you an active C programmer? There is a large section of that
community that is still deeply antagonistic to C99 and legacy C code is
likely to be around for many years more.


>
> The whole point of my email was in making it easy to write clean,
> portable C/C++ code.

There is no such beast. There is a subset of C that can be used cleanly
as C++ and WG14 and WG21 have co-operated to try to keep that as large
as possible whilst not prejudicing the language they are responsible for.

We have always known that writing compatible code is hard work. Making
it appear easier than it actually is will do no-one any favours. It will
just result in subtle, hard to detect bugs.

Note that we already have too many people who think that they can link a
C library to C++ just be using extern "C" and the headers. Strictly
speaking you cannot even do that in C. Nonetheless most implementations
happily link potentially incompatible code and most of the time it works.



   That was possible in C90/C++98, but the failure
> of C++ to support some of the new constructs in C99 is hampering
> that.  (And I'm not talking about more specialised constructs such as
> _Complex, although fixing to be fully interchangeable with
> std::complex<>  would be nice; nor am I talking about VLAs, as such
> things rarely occur in headers.)

And there you have a fundamental design issue. C has to add fundamental
types because it has no mechanism for adding true first class user
defined types. C++ only adds a fundamental type when that is essential
(e.g. bool where the comparison operators need to use it)

>
> I don't subscribe to be view that macros are evil and must be avoided,
> but frequent use of them rapidly makes code hard to understand.  But
> equally, if the common subset of the languages supported by the
> compilers you care about doesn't include the functionality you want,
> macros are essential to ensure portability.  Which leads to a choice:
> either you can write portable C/C++ code or you can write clean C/C++
> code.  The fact that the standards force you to that choice, even for
> a construct as simple as a boolean type, seems to me to be
> fundamentally misguided.

If you want to safely mix and match languages without much effort you
need far more support from the implementations than either language can
specify.

Make restrict a keyword in C++ and provide it with the same semantics as
in C99 (if we could actually determine what those are -- my C colleagues
are far from in agreement about this) and every C++ implementation would
have to add that complexity to already overworked compilers. Far better,
IMHO, to leave it out until such time as people can agree as to what it
should and can do. Do not waste time telling me what you think it does.
I know what was intended, but I also no that the reality is much less
and it makes promises that cannot always be kept.

Francis


--
[ comp.std.c++ is moderated.  To submit articles, try posting with your ]
[ newsreader.  If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]