Discussion:
Problem with windef.h
(too old to reply)
Wolfgang Jehuda Waeltermann
2010-03-02 16:12:43 UTC
Permalink
There is a problem with windef.h:

insinde the extern "C" block there is a

#ifndef NT_INCLUDED
#include <winnt.h>
#endif

which brings a lot of trouble to me:

Including windows.h from inside c++ namespace definitions switched the
linkage to extern C, then C 99 files like string.h include cstring (in case
of c++) where I get into trouble when trying to overload functions.

Can someone change the desired include to be included before extern C?
Wolfgang Jehuda Waeltermann
2010-03-02 17:18:13 UTC
Permalink
Note:

To get on with work I changed it in my file to

#ifndef NT_INCLUDED
#ifdef __cplusplus
} // close extern "C"
#endif /* __cplusplus */

#include <winnt.h>

#ifdef __cplusplus
extern "C" { // reopen extern C
#endif /* __cplusplus */
#endif


this works for me but someone has to change it.
David Golub
2010-03-02 20:58:17 UTC
Permalink
The Win32 API is not part of a namespace, and Win32 headers should not be
included from inside one. If you look at the official Microsoft
implementation, winnt.h is included from within the extern "C" block in
windef.h. The MinGW headers do the same thing. There is no reason to
expect that the code you are proposing would compile with any Win32 headers,
Open Watcom or otherwise.

David Golub
Post by Wolfgang Jehuda Waeltermann
To get on with work I changed it in my file to
#ifndef NT_INCLUDED
#ifdef __cplusplus
} // close extern "C"
#endif /* __cplusplus */
#include <winnt.h>
#ifdef __cplusplus
extern "C" { // reopen extern C
#endif /* __cplusplus */
#endif
this works for me but someone has to change it.
Wolfgang Jehuda Waeltermann
2010-03-02 21:57:11 UTC
Permalink
Current string.h does include cstring which shows the problems when extended
to functions not allowed in C. So then this behaviour must be changed. I
wonder anyway why sttring.h - designed for use with C - includes cstring
which is designed for use with C++ (since now it uses language extensions
not available to C).
So the other way would be to I open the recursive inclusions of those
currently used, does anybody know why it has been done?

Jehuda
Post by David Golub
The Win32 API is not part of a namespace, and Win32 headers should not be
included from inside one. If you look at the official Microsoft
implementation, winnt.h is included from within the extern "C" block in
windef.h. The MinGW headers do the same thing. There is no reason to
expect that the code you are proposing would compile with any Win32
headers, Open Watcom or otherwise.
David Golub
Post by Wolfgang Jehuda Waeltermann
To get on with work I changed it in my file to
#ifndef NT_INCLUDED
#ifdef __cplusplus
} // close extern "C"
#endif /* __cplusplus */
#include <winnt.h>
#ifdef __cplusplus
extern "C" { // reopen extern C
#endif /* __cplusplus */
#endif
this works for me but someone has to change it.
Wolfgang Jehuda Waeltermann
2010-03-02 23:12:22 UTC
Permalink
To be more specific: It's not inside a namespace. The problem is the fact
that only one function with a particular name can have C linkage. While
during the past none of the C 99 functions was overloaded it has not been a
problem when string.h refers to cstring (and so with stdlib and others).

With c++0x there are functions which will be overloaded while in C99 the
cannot be. That also shows that with the upcoming standard mixing C99
headers and C++ headers should be avoided not only by programmers but also
by the library implementation as well.
The current compile fails because I have functions overloaded, but due to
the chain winnt.h -> string.h -> cstring the compiler complains about a
function already declared.

To solve this (and other related problems) there are different ways, after
reviewing this for hours now I think the best approach is to not declare or
shift all C99 functions by default into namespace std. If they stay in
global namespace the newer declarations can be done with C++ linkage and
refering to the C implementation.

To give an example if my english is not good enough to poitn things out):

abs, labs and llabs are C99 and C++ (past)

In upcoming standard abs will be overloaded.

Overloading abs is impossible when beeing in language C linkage.

My current solution is to have abs, labs and llabs declared in namespace
c++0_hide with external linkage (could be also watcom, temp, C99 or whatever
name you like).
All abs are declared standard C++, namespace std and overloaded and calling
c++0_hide::abs, c++0_hide::labs etc.and I remove any include where C99 fiels
are including C+0x headers. The opposite can be done but still adjustments
need to be done since not all of the C99 functions are taken 1:1 to C++0 but
instead some functions are defined different (mostly overloaded). So I put
the current C99 headers out of namespace std and shift in what is needed.
That works, no new lib function is needed, only 3 inline wrappers. The thing
only gets messy when a header supposed with open extern C linkage is
including cstring since a name can only be used once. That's why now I adde
an error pragmas when inside non-C99 compliant c++0x headers defines of C99
headers are found (like I do now in cstring when string.h was included).
Post by David Golub
The Win32 API is not part of a namespace, and Win32 headers should not be
included from inside one. If you look at the official Microsoft
implementation, winnt.h is included from within the extern "C" block in
windef.h. The MinGW headers do the same thing. There is no reason to
expect that the code you are proposing would compile with any Win32
headers, Open Watcom or otherwise.
David Golub
Post by Wolfgang Jehuda Waeltermann
To get on with work I changed it in my file to
#ifndef NT_INCLUDED
#ifdef __cplusplus
} // close extern "C"
#endif /* __cplusplus */
#include <winnt.h>
#ifdef __cplusplus
extern "C" { // reopen extern C
#endif /* __cplusplus */
#endif
this works for me but someone has to change it.
David Golub
2010-03-03 01:13:41 UTC
Permalink
I'm not clear on what you're trying to do. Could you provide code to
reproduce the problem? Are you attempting to define a function that
overloads a function in string.h or cstring? As I said before, the
Microsoft and MinGW headers work the same, so this error would occur with
any Win32 headers that in existence, as far as I know. If C++0x does what
you say, then it may be necessary to modify the runtime library headers so
that string.h would not longer include cstring.

In answer to your question, my understanding is that the current C++
standard explicitly permits xxxx.h to include cxxxx when compiling in C++
mode.

David Golub
Post by Wolfgang Jehuda Waeltermann
To be more specific: It's not inside a namespace. The problem is the fact
that only one function with a particular name can have C linkage. While
during the past none of the C 99 functions was overloaded it has not been
a problem when string.h refers to cstring (and so with stdlib and others).
With c++0x there are functions which will be overloaded while in C99 the
cannot be. That also shows that with the upcoming standard mixing C99
headers and C++ headers should be avoided not only by programmers but also
by the library implementation as well.
The current compile fails because I have functions overloaded, but due to
the chain winnt.h -> string.h -> cstring the compiler complains about a
function already declared.
To solve this (and other related problems) there are different ways, after
reviewing this for hours now I think the best approach is to not declare
or shift all C99 functions by default into namespace std. If they stay in
global namespace the newer declarations can be done with C++ linkage and
refering to the C implementation.
abs, labs and llabs are C99 and C++ (past)
In upcoming standard abs will be overloaded.
Overloading abs is impossible when beeing in language C linkage.
My current solution is to have abs, labs and llabs declared in namespace
c++0_hide with external linkage (could be also watcom, temp, C99 or
whatever name you like).
All abs are declared standard C++, namespace std and overloaded and
calling c++0_hide::abs, c++0_hide::labs etc.and I remove any include where
C99 fiels are including C+0x headers. The opposite can be done but still
adjustments need to be done since not all of the C99 functions are taken
1:1 to C++0 but instead some functions are defined different (mostly
overloaded). So I put the current C99 headers out of namespace std and
shift in what is needed. That works, no new lib function is needed, only 3
inline wrappers. The thing only gets messy when a header supposed with
open extern C linkage is including cstring since a name can only be used
once. That's why now I adde an error pragmas when inside non-C99 compliant
c++0x headers defines of C99 headers are found (like I do now in cstring
when string.h was included).
Post by David Golub
The Win32 API is not part of a namespace, and Win32 headers should not be
included from inside one. If you look at the official Microsoft
implementation, winnt.h is included from within the extern "C" block in
windef.h. The MinGW headers do the same thing. There is no reason to
expect that the code you are proposing would compile with any Win32
headers, Open Watcom or otherwise.
David Golub
Post by Wolfgang Jehuda Waeltermann
To get on with work I changed it in my file to
#ifndef NT_INCLUDED
#ifdef __cplusplus
} // close extern "C"
#endif /* __cplusplus */
#include <winnt.h>
#ifdef __cplusplus
extern "C" { // reopen extern C
#endif /* __cplusplus */
#endif
this works for me but someone has to change it.
Peter C. Chapin
2010-03-03 03:40:14 UTC
Permalink
Post by David Golub
In answer to your question, my understanding is that the current C++
standard explicitly permits xxxx.h to include cxxxx when compiling in C++
mode.
I went to some trouble to create headers that conform accurately to the
C++1998 and C++2003 standards in regards to the handling of namespaces. In
particular...

In C++, the <cname> headers *only* introduce the standard names into namespace
std. They do not introduce the standard names into the global namespace
(doing so was forbidden according to the existing standard). However, the
<name.h> headers introduce the standard names in both namespace std and the
global namespace. That's what our current implementation does. They do this
by #including the corresponding <cname> header and then apply using
declarations to hoist the names out of namespace std into the global space.
This is specifically allowed by the existing standard.

In C, the <name.h> headers just introduce the names in the global namespace
directly and, naturally, don't mess around with namespace std. Note the
conditional compilation directives in the file that cause C and C++ to see
different material.

Most library providers were lazy in this regard and did things the other way
around. They provided <cname> headers that included the corresponding
<name.h> header and then applied using declarations to inject the standard
names into namespace std. For example

#include <cstdio>

int main( )
{
printf("Hello, World!\n");
return 0;
}

The above does not compile with Open Watcom. The name "printf" needs to be
qualified like this: std::printf. However it *does* compile with certain
other compilers such as g++ and Visual C++... despite the fact that the
existing standard clearly forbids such usage. I've seen discussion on the C++
newsgroup about how the standard's requirements are "impossible" to
implement, etc, but frankly I don't see it. Aside from being a bit tedious,
it wasn't rocket science to set it up.

Anyway the new standard specifically allows either approach. It
is "unspecified" if the <name.h> headers hoist standard names out of
namespace std or if the <cname> headers inject names into namespace std. Our
implementation still conforms, but then so do the sloppy ones too. Ah well.

To the issue at hand. Jehuda I also don't quite follow what you mean. If you
could provide a short code sample of something that doesn't compile but
should, that would be helpful.

Regarding overloading... the names std::abs, std::labs, etc, are already being
overloaded in C++ code... as required by the existing standard. Setting it up
was a bit tricky as I recall but again, not rocket science. If there are new
functions in C++0x that overload with C99 functions I imagine we could set it
up similarly. Take a look at bld\hdr\watcom\stdlib.mh and see what you think.

Peter
Jonathan de Boyne Pollard
2010-03-03 21:05:39 UTC
Permalink
I've seen discussion on the C++ newsgroup about how the standard's
requirements are "impossible" to implement, etc, but frankly I don't
see it. Aside from being a bit tedious, it wasn't rocket science to
set it up.
I agree.
Wolfgang Jehuda Waeltermann
2010-03-03 08:07:37 UTC
Permalink
Okay, I'll do my best :)

File: IncErr.Hpp

namespace test {

void somefunc (int n);
void somefunc (float f);
}


File: IncErr.h

extern "C" {

void somefunc (int n);

#include "IncErr.hpp"
}


Thats all you need. I didn't include the usual __cplusplus ifelse and
other stuff since they are not part of the problem.

Now include IncErr.hpp - it will compile. Simply overloading a function.

Next only include IncErr.h which includes IncErr.hpp - now IncErr.hpp
will be compiled with extern linkage C - so it will fail since there can
only be one particular name with such linkage.

Since C99 now becomes a real "subset" of C++ I suggest that C99 files do
not include C++ files but vice versa. The complete implementation would
look something like this:


File: IncErr.Hpp

#include "IncErr.h"

namespace test {

void somefunc (int n) { ::somefunc (n); }
void somefunc (float f) { ....}
}


File: IncErr.h

extern "C" {

void somefunc (int n);
}


I hope now it becomes more clearer. Please be patient with me. Reading
my last post again it's even difficult for myself to understand -
probably because I try to translate my (complicated) thinking 1:1 into
another language :)

Jehuda
Post by David Golub
I'm not clear on what you're trying to do. Could you provide code to
reproduce the problem? Are you attempting to define a function that
overloads a function in string.h or cstring? As I said before, the
Microsoft and MinGW headers work the same, so this error would occur
with any Win32 headers that in existence, as far as I know. If C++0x
does what you say, then it may be necessary to modify the runtime
library headers so that string.h would not longer include cstring.
In answer to your question, my understanding is that the current C++
standard explicitly permits xxxx.h to include cxxxx when compiling in
C++ mode.
David Golub
Post by Wolfgang Jehuda Waeltermann
To be more specific: It's not inside a namespace. The problem is the
fact that only one function with a particular name can have C
linkage. While during the past none of the C 99 functions was
overloaded it has not been a problem when string.h refers to cstring
(and so with stdlib and others).
With c++0x there are functions which will be overloaded while in C99
the cannot be. That also shows that with the upcoming standard mixing
C99 headers and C++ headers should be avoided not only by programmers
but also by the library implementation as well.
The current compile fails because I have functions overloaded, but
due to the chain winnt.h -> string.h -> cstring the compiler
complains about a function already declared.
To solve this (and other related problems) there are different ways,
after reviewing this for hours now I think the best approach is to
not declare or shift all C99 functions by default into namespace std.
If they stay in global namespace the newer declarations can be done
with C++ linkage and refering to the C implementation.
abs, labs and llabs are C99 and C++ (past)
In upcoming standard abs will be overloaded.
Overloading abs is impossible when beeing in language C linkage.
My current solution is to have abs, labs and llabs declared in
namespace c++0_hide with external linkage (could be also watcom,
temp, C99 or whatever name you like).
All abs are declared standard C++, namespace std and overloaded and
calling c++0_hide::abs, c++0_hide::labs etc.and I remove any include
where C99 fiels are including C+0x headers. The opposite can be done
but still adjustments need to be done since not all of the C99
functions are taken 1:1 to C++0 but instead some functions are
defined different (mostly overloaded). So I put the current C99
headers out of namespace std and shift in what is needed. That works,
no new lib function is needed, only 3 inline wrappers. The thing only
gets messy when a header supposed with open extern C linkage is
including cstring since a name can only be used once. That's why now
I adde an error pragmas when inside non-C99 compliant c++0x headers
defines of C99 headers are found (like I do now in cstring when
string.h was included).
Post by David Golub
The Win32 API is not part of a namespace, and Win32 headers should
not be included from inside one. If you look at the official
Microsoft implementation, winnt.h is included from within the extern
"C" block in windef.h. The MinGW headers do the same thing. There
is no reason to expect that the code you are proposing would compile
with any Win32 headers, Open Watcom or otherwise.
David Golub
Post by Wolfgang Jehuda Waeltermann
To get on with work I changed it in my file to
#ifndef NT_INCLUDED
#ifdef __cplusplus
} // close extern "C"
#endif /* __cplusplus */
#include <winnt.h>
#ifdef __cplusplus
extern "C" { // reopen extern C
#endif /* __cplusplus */
#endif
this works for me but someone has to change it.
Anthony Williams
2010-03-03 08:25:46 UTC
Permalink
Post by Wolfgang Jehuda Waeltermann
Okay, I'll do my best :)
File: IncErr.Hpp
namespace test {
void somefunc (int n);
void somefunc (float f);
}
File: IncErr.h
extern "C" {
void somefunc (int n);
#include "IncErr.hpp"
}
Even without the overload for float, this is invalid if the two headers
are included in the same program, since test::somefunc(int) would be
declared with different linkage in each case.

It is a bad idea to include headers inside a linkage specification, just
like it is a bad idea to include headers inside a namespace definition.

If you really want to write code like that then wrap the C++ code in an
extern "C++" block:

//IncErr.hpp
extern "C++" {
namespace test {
void somefunc(int n);
void somefunc(float f);
}
}

Anthony
--
Author of C++ Concurrency in Action http://www.stdthread.co.uk/book/
just::thread C++0x thread library http://www.stdthread.co.uk
Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976
Wolfgang Jehuda Waeltermann
2010-03-03 08:53:37 UTC
Permalink
I know it's a bad idea, that's why I initially started to ask for the
change of winnt.h. I wondered why someone did it but as it was statet
the header is used that way in other implementations as well.

The program compiles and links with no errors at my place since C++
linkage is the default - but I don't know if that's standard, compiler
switch related or OW style. I had the C++ linkage in mind as a explicit
declaration so your code goes towards an explicit error prevention if
linkage is different by default. Thanks!


Anthony Williams <***@gmail.com> wrote in news:hml6eb$ntc$***@www.openwatcom.org:

<snip snip>
Post by Anthony Williams
It is a bad idea to include headers inside a linkage specification,
just like it is a bad idea to include headers inside a namespace
definition.
If you really want to write code like that then wrap the C++ code in
//IncErr.hpp
extern "C++" {
namespace test {
void somefunc(int n);
void somefunc(float f);
}
}
Anthony
Peter C. Chapin
2010-03-03 11:15:56 UTC
Permalink
Post by Anthony Williams
Even without the overload for float, this is invalid if the two headers
are included in the same program, since test::somefunc(int) would be
declared with different linkage in each case.
Actually it is legal because the 'extern "C"' linkage propagates to the
functions inside the name space. For example the following compiles with both
g++ and Open Watcom:

extern "C" {
void some_function( int x );

namespace example {
void some_function( int x );
}
}

Despite the fact that declaration appears in two namespaces there is only one
function and that function is extern "C". I believe there are even examples
in the standard that illustrate this.

When you try to add an overload inside the namespace you get errors because
there can be only one function of a given name with extern "C" linkage. It's
the same as trying to do

extern "C" {
void some_function( int x );
void some_function( float x );
}

It doesn't matter if a namespace is involved or not.

It sounds like Jehuda is concerned about cases where a function defined by the
C standard is provided overloads in C++.

For example, in cstdlib:

// C library functions are in namespace std but have extern "C" linkage.
extern "C" {
namespace std {
int abs( int );
}
}

#ifndef _INCLUDED_FROM_STDLIB_H
// C++ also has this overload. This version is not extern "C" and so can
// coexist with the C library version. However, this declaration is not
// visible when stdlib.h is used.
namespace std {
long abs( long );
}
#endif


Then in stdlib.h:

// In C++ hoist the standard names from namespace std in <cstdlib>
#ifdef __cplusplus
#define _INCLUDED_FROM_STDLIB_H
#include <cstdlib>
#undef _INCLUDED_FROM_STDLIB_H
using std::abs

// In C just declare the names directly.
#else
int abs( int );
#endif


A C++ program that includes <stdlib.h> does not see the overloads for abs, but
that's okay because the standard doesn't require that (as far as I can
interpret). If a C++ program wants to use the abs overloads it must include
<cstdlib>. C++ code should be using the <cname> headers anyway. The name.h
headers exist only for legacy support (that is, for compiling C code as C++).

Peter
Anthony Williams
2010-03-03 12:56:33 UTC
Permalink
Post by Peter C. Chapin
Post by Anthony Williams
Even without the overload for float, this is invalid if the two headers
are included in the same program, since test::somefunc(int) would be
declared with different linkage in each case.
Actually it is legal because the 'extern "C"' linkage propagates to the
functions inside the name space. For example the following compiles with both
extern "C" {
void some_function( int x );
namespace example {
void some_function( int x );
}
}
Yes, that's legal. It's also not what I meant.

extern "C" {
namespace example {
void some_function( int x );
}
}
namespace example {
void some_function( int x );
}

is illegal, and is what you get if you include a header inside an extern
"C" declaration in one source file, and on its own in another.

Anthony
--
Author of C++ Concurrency in Action http://www.stdthread.co.uk/book/
just::thread C++0x thread library http://www.stdthread.co.uk
Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk
15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976
Wolfgang Jehuda Waeltermann
2010-03-04 13:27:05 UTC
Permalink
<snip>
Post by Peter C. Chapin
It sounds like Jehuda is concerned about cases where a function defined by the
C standard is provided overloads in C++.
YES! That's the point :)

Peter C. Chapin
2010-03-03 11:30:16 UTC
Permalink
Post by Wolfgang Jehuda Waeltermann
Since C99 now becomes a real "subset" of C++ I suggest that C99 files do
not include C++ files but vice versa. The complete implementation would
File: IncErr.Hpp
#include "IncErr.h"
namespace test {
void somefunc (int n) { ::somefunc (n); }
void somefunc (float f) { ....}
}
It's a little more elegant to apply a using declaration to inject names from
another namespace rather than writing an inline forwarding function.

#include "IncErr.h"

namespace test {
using ::somefunc;
void somefunc( float f );
}

What you are proposing is what several other major libraries do but it's what
I went to significant trouble to avoid. The problem with this approach is
that when you include a C++ only header you get major pollution of the global
namespace. For example with g++ doing

#include <cstdio>

populates the global namespace with all the names from the C library. It
injects those names into namespace std just fine, but there is still
namespace pollution. In contract with my implementation the same include
provides the C library names *only* in namespace std (except for the macros,
of course). In fact, this behavior is required by the existing C++ standard.

Discussions on various C++ forums about this made it clear that most people
don't know that it is perfectly fine to declare an extern "C" function in a
namespace. Most people seemed to think that it was necessary to implement two
versions of each C library function... one for the global namespace and one
for namespace std. Clearly that would be a tedious and costly exercise.
However, it is not necessary to do that. There is only one C library; the
namespace in which its functions are declared is a separate matter.

namespace X {
namespace Y {
extern "C" int printf( const char *, ... );
}
}

I can now access the C library function printf as X::Y::printf.

As I said there are examples in the C++ standard that illustrate this quite
directly.

Peter
Wolfgang Jehuda Waeltermann
2010-03-03 12:27:09 UTC
Permalink
<snip>
Post by Peter C. Chapin
What you are proposing is what several other major libraries do but
it's what I went to significant trouble to avoid. The problem with
this approach is that when you include a C++ only header you get major
pollution of the global namespace. For example with g++ doing
#include <cstdio>
populates the global namespace with all the names from the C library.
It injects those names into namespace std just fine, but there is
still namespace pollution. In contract with my implementation the same
include provides the C library names *only* in namespace std (except
for the macros, of course). In fact, this behavior is required by the
existing C++ standard.
I know what you mean. New standard leaves it undefined wether that is
done or not but pollution should be avoided I agree.

The way you did it with stdlib works and so it's okay.

I was mainly worried not only about the compiler error but about the
mixing of the two headers. Maybe that's because I use to strictly
seperate things like that and never extensively used defines to change
compile flow in same files depending on their way of inclusion-
A typicle Jehuda-solution would probably result in three files:
name.h, cname and _name.h, the last one including declarations which are
used by both implementations but without including anything and the
first two include neccessary files before that, include the third and
add additional stuff as needed. But maybe that looks too organized in
some way or too unefficient the other way - or it's because I'm just too
dump regaring multiple define depending includes :)

I'll take your example of stdlib for those similar complications I see
and will try the other way where those overlapping hasn't took place
yet. So when it comes to the time to include what I have ready this
hopefully reduces adjustments to other files (like C headers). Still a
lot of work in front of me so this topic is not urgent anyway. But maybe
it is worth talking about it to have a structered way how includes are
build and done.


Jehuda
Jonathan de Boyne Pollard
2010-03-03 21:05:43 UTC
Permalink
I didn't include the usual __cplusplus ifelse and other stuff since
they are not part of the problem.
Actually it's very much part of the issue. It's a fundamental part of
how the existing mechanism works and does the right thing in both
languages.
Loading...