Re: Including C Header in a namespace

Discussion in 'C++' started by James Kanze, May 29, 2010.

  1. James Kanze

    James Kanze Guest

    On May 28, 10:20 am, Markus Raab <> wrote:
    > Victor Bazarov wrote:
    > >> For struct, enum or typedefs there should be no problem at
    > >> all, it should get a new name inside C++ and extern "C"
    > >> should have no effect. Is this correct?


    > > Any name that can have linkage will be affected.


    > Is it possible that a struct or enum have linkage?


    Formally, the answer is no. But I don't think this is what you
    mean. Types, variables and functions don't have linkage; names
    have linkage. And in C++, the name of a struct or an enum (or
    any other type) can only have external linkage. That's one of
    the reasons unnamed namespaces were introduced; so that you can
    define a struct, enum or class that isn't accessible from
    another translation unit.

    This is one place where C and C++ differ.

    > >> Did anyone ever put a C-Header file into a namespace?


    > > Probably. It's very hard to prove a negative statement.


    > >> Is this a good idea?


    > > I don't think so. What would it accomplish?


    > So that an existing C++ programs can have typedefs, enums and
    > functions with the same names in the global namespace.


    I'm not sure what the compiler is supposed to do with the names
    introduced by typedef's or enums in an `extern "C"' namespace,
    since they aren't visible in C. (A typedef isn't visible
    outside the translation unit, period; a name defined by a
    typedef declaration has internal linkage. But... a typedef is
    nothing but an alias for a type, and the name of the type is
    aliases has external linkage.)

    > E.g. there is a program which has already a typedefs like:
    > typedef struct InternalKey Key;
    > or an enums like:
    > enum {
    > KEY_END=SDL_KEY_END,
    > };


    > And now I want to include a C-Header file which uses the same
    > names (Key and KEY_END). My idea was to put this C-Header in a
    > namespace to avoid such name-clashes.


    Interesting idea. It should work, but I think it would be more
    natural to do the reverse: put the C++ definitions in a
    namespace.

    Note that namespaces work as usual, and ignore linkage
    specifications, during name lookup. However:

    At most one function with a particular name can have C
    language linkage. Two declarations for a function with C
    language linkage with the same function name (ignoring
    the namespace names that qualify it) that appear in
    different namespace scopes refer to the same function.
    Two declarations for an object with C language linkage
    with the same name (ignoring the namespace names that
    qualify it) that appear in different namespace scopes
    refer to the same object.

    In other words, given:

    namespace A { extern "C" void f(); }

    , the C++ compiler should treat the name of the function as
    A::f. However, this A::f and a B::f declared identically in a
    different translation unit refer to the same function.

    > >> [..]

    >
    > >> Is there any difference between the next two lines?
    > >> extern "C" { namespace yyy { }}
    > >> namespace yyy { extern "C" { }}


    > > The former looks wrong (although it probably isn't) <g>.
    > > You need to keep in mind that 'extern "C"' removes the
    > > namespace (yyy) in your case from the name. The namespaces
    > > are *ignored* (see 7.5/6). I believe both are OK. The
    > > names of anything inside the inner curly braces will *not*
    > > have 'yyy::' as a part of it.


    > Ohh, ok thank you. Does the standard says it is ignored in any
    > case or only when there are problems at symbol level?


    The standard says that it is not ignored at all. But that the
    results might not be what you want.

    Rather than trying to count the angels on the head of a pin in
    the standard, wouldn't it be a better idea just to not do
    either?

    --
    James Kanze
     
    James Kanze, May 29, 2010
    #1
    1. Advertising

  2. * James Kanze, on 29.05.2010 22:58:
    > On May 28, 10:20 am, Markus Raab<> wrote:
    >> Victor Bazarov wrote:
    >>>> For struct, enum or typedefs there should be no problem at
    >>>> all, it should get a new name inside C++ and extern "C"
    >>>> should have no effect. Is this correct?

    >
    >>> Any name that can have linkage will be affected.

    >
    >> Is it possible that a struct or enum have linkage?

    >
    > Formally, the answer is no. But I don't think this is what you
    > mean. Types, variables and functions don't have linkage; names
    > have linkage. And in C++, the name of a struct or an enum (or
    > any other type) can only have external linkage. That's one of
    > the reasons unnamed namespaces were introduced; so that you can
    > define a struct, enum or class that isn't accessible from
    > another translation unit.
    >
    > This is one place where C and C++ differ.


    Hm, I had to read the above 3 times. It's correct, but a hasty reading can yield
    a false impression. So to summarize in clear-speech, in C++98 a struct type can
    have external linkage or, if it is a local struct type (in a function), no
    linkage. The latter can't be used as an actual template parameter since it
    doesn't have linkage. As I recall this will be fixed in C++0x?


    >>>> Did anyone ever put a C-Header file into a namespace?

    >
    >>> Probably. It's very hard to prove a negative statement.

    >
    >>>> Is this a good idea?

    >
    >>> I don't think so. What would it accomplish?

    >
    >> So that an existing C++ programs can have typedefs, enums and
    >> functions with the same names in the global namespace.

    >
    > I'm not sure what the compiler is supposed to do with the names
    > introduced by typedef's or enums in an `extern "C"' namespace,
    > since they aren't visible in C. (A typedef isn't visible
    > outside the translation unit, period; a name defined by a
    > typedef declaration has internal linkage. But... a typedef is
    > nothing but an alias for a type, and the name of the type is
    > aliases has external linkage.)


    It's a difficult thing to do. I once put a large part of <windows.h> in a
    namespace 'win32', for code that did Windows security checking, handling ACLs
    and doing impersonation and such, wrapped in an ActiveX control (i.e., it used a
    pretty large part of the Windows API). It was fragile because Microsoft defines
    a lot of things as macros, but the frequency of revisions of the wrapping
    dropped to near zero as I coded away, so, it's doable. It was necessary to first
    include all the standard headers that <windows.h> relies on. Happily it wasn't
    more than 4 or 5, as I recall. I then got into a heated Usenet discussion with
    the guy who introduced 'explicit' in the language. He maintained that what I did
    was impossible... :)

    Of course it broke a lot of language rules.

    And I wouldn't do it today -- but although it was a braindead thing to do it
    was a worthwhile exercise: I learned a lot (but most of it forgotten now).


    [snip]


    Cheers,

    - Alf


    --
    blog at <url: http://alfps.wordpress.com>
     
    Alf P. Steinbach, May 29, 2010
    #2
    1. Advertising

  3. James Kanze

    Öö Tiib Guest

    On 31 mai, 21:21, Markus Raab <> wrote:
    > James Kanze wrote:
    > >> >> Is there any difference between the next two lines?
    > >> >> extern "C" { namespace yyy { }}
    > >> >> namespace yyy { extern "C" { }}

    >
    > >> > The former looks wrong (although it probably isn't) <g>.
    > >> > You need to keep in mind that 'extern "C"' removes the
    > >> > namespace (yyy) in your case from the name.  The namespaces
    > >> > are *ignored* (see 7.5/6).  I believe both are OK.  The
    > >> > names of anything inside the inner curly braces will *not*
    > >> > have 'yyy::' as a part of it.

    >
    > >> Ohh, ok thank you. Does the standard says it is ignored in any
    > >> case or only when there are problems at symbol level?

    >
    > > The standard says that it is not ignored at all.  But that the
    > > results might not be what you want.

    >
    > > Rather than trying to count the angels on the head of a pin in
    > > the standard, wouldn't it be a better idea just to not do
    > > either?

    >
    > I would also be interested if the approach actually works in the major
    > compilers. If it is not a good idea I will discard it. Maybe someone has
    > another idea?


    What about the "usual" idea to use prefixes in C names instead of
    trying to use namespaces that C does not have?

    IOW in C++ code write:

    extern "C" { void yyy_f(); }

    Instead of:

    namespace yyy { extern "C" { void f(); }}
     
    Öö Tiib, Jun 1, 2010
    #3
  4. James Kanze

    Öö Tiib Guest

    On Jun 1, 10:24 am, Markus Raab <> wrote:
    > Öö Tiib wrote:
    > > What about the "usual" idea to use prefixes in C names instead of
    > > trying to use namespaces that C does not have?

    >
    > > IOW in C++ code write:

    >
    > > extern "C" { void yyy_f(); }

    >
    > > Instead of:

    >
    > > namespace yyy { extern "C" { void f(); }}

    >
    > They are already prefixed, but in some cases there could be still name
    > clashes, e.g. KEY_END (KEY_ is the prefix).
    >
    > And of course there is lots of existing code already using the names as they
    > are...


    Yes. In C you can not have overloads. Namespaces do not help since
    these are not part of C interface. 'extern "C"' means that what you
    declare is C interface (so no namespaces apply).

    The problem is that if you have different libraries where extern C
    function names clash then you can not link them directly together and
    expect that it works. You have to either rename the clashing functions
    (add more prefixes) or enwrap them (i explain briefly) or avoid using
    them in same program.

    Enwrapping can be done for example with shared library module that
    links with one bad library (with clashing names) but does not export
    the clashing names. Then rest of the program links with that shared
    library and not with the original bad library.
     
    Öö Tiib, Jun 1, 2010
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Stanimir Stamenkov
    Replies:
    3
    Views:
    1,296
    Stanimir Stamenkov
    Apr 25, 2005
  2. Replies:
    1
    Views:
    525
    George Bina
    Jul 20, 2006
  3. mlt
    Replies:
    2
    Views:
    880
    Jean-Marc Bourguet
    Jan 31, 2009
  4. tan
    Replies:
    2
    Views:
    309
    Default User
    May 28, 2010
  5. Victor Bazarov

    Re: Including C Header in a namespace

    Victor Bazarov, May 28, 2010, in forum: C++
    Replies:
    0
    Views:
    751
    Victor Bazarov
    May 28, 2010
Loading...

Share This Page