extern "C" friend function without external linkage

Discussion in 'C++' started by Stanisław Findeisen, Aug 25, 2010.

  1. Hi

    I am trying to define an extern "C" friend function without external
    linkage. The idea is to pass this function to pthread_once and use it
    for initialization of a singleton object in a multithreaded program.

    I don't want external linkage because I don't want other parts of the
    program to be able to call this initialization function.

    Here is an example that does no pthread_once call but uses extern "C".
    The point, after all, is to have C linkage.

    ========== MyClass.h BEGIN ==========
    #ifdef UGLY_UGLY_UGLY_MyClass_implementation_is_here
    extern "C" {
    static void changeX();
    }
    #endif

    class MyClass {
    public:
    static void printX();
    private:
    friend void changeX();
    static int x;
    };

    extern "C" void testChangeX();
    ========== MyClass.h END ============

    ========== MyClass.cpp BEGIN ==========
    #include <iostream>
    #define UGLY_UGLY_UGLY_MyClass_implementation_is_here
    #include "MyClass.h"

    int MyClass::x = 5;

    void MyClass::printX() {
    std::cout << "x is now: " << x << std::endl;
    }

    extern "C" void changeX() {
    MyClass::x = 7;
    }

    extern "C" void testChangeX() {
    changeX();
    }
    ========== MyClass.cpp END ============

    ========== test-friend.cpp BEGIN ============
    #include "MyClass.h"

    int main() {
    MyClass::printX();
    changeX();
    testChangeX();
    MyClass::printX();

    return 0;
    }
    ========== test-friend.cpp END ==============

    ========== Makefile BEGIN ==============
    ..PHONY: default
    default:
    g++ -Wall -c MyClass.cpp -o MyClass.o
    g++ -Wall -c test-friend.cpp -o test-friend.o
    g++ -Wall -o test-friend.out MyClass.o test-friend.o

    ..PHONY: clean
    clean:
    rm -f MyClass.o
    rm -f test-friend.o
    rm -f test-friend.out
    ========== Makefile END ==============

    Here changeX is the secret initialization function, and testChangeX
    simulates pthreads library C code that changeX is called from
    (testChangeX has external linkage and that's no problem).

    It *WORKS* here (the program does not compile until I delete changeX
    call from main()), but as you can see, this is quite ugly. The question
    is how to simplify this.

    Explanation:

    1. changeX() declaration at the beginning of MyClass.h seems necessary,
    because without it my compiler complains:

    > MyClass.h: In function ‘void changeX()’:
    > MyClass.h:11: error: previous declaration of ‘void changeX()’ with ‘C++’ linkage
    > MyClass.cpp:11: error: conflicts with new declaration with ‘C’ linkage


    I think that's because of the Standard saying (11.4.3):

    > A function first declared in a friend declaration has external linkage (3.5). Otherwise, the function retains its previous linkage (7.1.1).


    2. The ugly macro helps to fix the problem of other (than MyClass.cpp)
    translation units encountering the declaration of changeX in MyClass.h.
    Each such case generates a warning:

    > MyClass.h:11: warning: ‘void changeX()’ declared ‘static’ but never defined


    Sooo, does anyone has an idea how to simplify this? :)

    You should be able to download the above source here:
    http://eisenbits.homelinux.net/~stf/load/20100825-friend-1.tgz .

    I am using g++ for this:

    g++ (Debian 4.3.2-1.1) 4.3.2
    Copyright (C) 2008 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions. There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    however I do care about POSIX compliance.

    STF

    http://eisenbits.homelinux.net/~stf/
    OpenPGP: DFD9 0146 3794 9CF6 17EA D63F DBF5 8AA8 3B31 FE8A
     
    Stanisław Findeisen, Aug 25, 2010
    #1
    1. Advertising

  2. On 2010-08-25 18:05, Stanisław Findeisen wrote:
    > Hi
    >
    > I am trying to define an extern "C" friend function without external
    > linkage. The idea is to pass this function to pthread_once and use it
    > for initialization of a singleton object in a multithreaded program.
    >
    > I don't want external linkage because I don't want other parts of the
    > program to be able to call this initialization function.
    >
    > Here is an example that does no pthread_once call but uses extern "C".
    > The point, after all, is to have C linkage.
    >
    > ========== MyClass.h BEGIN ==========
    > #ifdef UGLY_UGLY_UGLY_MyClass_implementation_is_here
    > extern "C" {
    > static void changeX();
    > }
    > #endif
    >
    > class MyClass {
    > public:
    > static void printX();
    > private:
    > friend void changeX();
    > static int x;
    > };
    >
    > extern "C" void testChangeX();
    > ========== MyClass.h END ============
    >
    > ========== MyClass.cpp BEGIN ==========
    > #include <iostream>
    > #define UGLY_UGLY_UGLY_MyClass_implementation_is_here
    > #include "MyClass.h"
    >
    > int MyClass::x = 5;
    >
    > void MyClass::printX() {
    > std::cout << "x is now: " << x << std::endl;
    > }
    >
    > extern "C" void changeX() {
    > MyClass::x = 7;
    > }
    >
    > extern "C" void testChangeX() {
    > changeX();
    > }
    > ========== MyClass.cpp END ============
    >
    > ========== test-friend.cpp BEGIN ============
    > #include "MyClass.h"
    >
    > int main() {
    > MyClass::printX();
    > changeX();
    > testChangeX();
    > MyClass::printX();
    >
    > return 0;
    > }
    > ========== test-friend.cpp END ==============
    >
    > ========== Makefile BEGIN ==============
    > .PHONY: default
    > default:
    > g++ -Wall -c MyClass.cpp -o MyClass.o
    > g++ -Wall -c test-friend.cpp -o test-friend.o
    > g++ -Wall -o test-friend.out MyClass.o test-friend.o
    >
    > .PHONY: clean
    > clean:
    > rm -f MyClass.o
    > rm -f test-friend.o
    > rm -f test-friend.out
    > ========== Makefile END ==============
    >
    > Here changeX is the secret initialization function, and testChangeX
    > simulates pthreads library C code that changeX is called from
    > (testChangeX has external linkage and that's no problem).
    >
    > It *WORKS* here (the program does not compile until I delete changeX
    > call from main()), but as you can see, this is quite ugly. The question
    > is how to simplify this.
    >
    > Explanation:
    >
    > 1. changeX() declaration at the beginning of MyClass.h seems necessary,
    > because without it my compiler complains:
    >
    >> MyClass.h: In function ‘void changeX()’:
    >> MyClass.h:11: error: previous declaration of ‘void changeX()’ with ‘C++’ linkage
    >> MyClass.cpp:11: error: conflicts with new declaration with ‘C’ linkage

    >
    > I think that's because of the Standard saying (11.4.3):
    >
    >> A function first declared in a friend declaration has external linkage (3.5). Otherwise, the function retains its previous linkage (7.1.1).

    >
    > 2. The ugly macro helps to fix the problem of other (than MyClass.cpp)
    > translation units encountering the declaration of changeX in MyClass.h.
    > Each such case generates a warning:
    >
    >> MyClass.h:11: warning: ‘void changeX()’ declared ‘static’ but never defined

    >
    > Sooo, does anyone has an idea how to simplify this? :)
    >
    > You should be able to download the above source here:
    > http://eisenbits.homelinux.net/~stf/load/20100825-friend-1.tgz .
    >
    > I am using g++ for this:
    >
    > g++ (Debian 4.3.2-1.1) 4.3.2
    > Copyright (C) 2008 Free Software Foundation, Inc.
    > This is free software; see the source for copying conditions. There is NO
    > warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    >
    > however I do care about POSIX compliance.


    Probably moving

    extern "C" {
    static void changeX();
    }

    declaration to MyClass.cpp helps a bit...

    STF

    http://eisenbits.homelinux.net/~stf/
    OpenPGP: DFD9 0146 3794 9CF6 17EA D63F DBF5 8AA8 3B31 FE8A
     
    Stanisław Findeisen, Aug 25, 2010
    #2
    1. Advertising

  3. Stanisław Findeisen

    Goran Pusic Guest

    On Aug 25, 6:14 pm, Stanis³aw Findeisen <> wrote:
    > On 2010-08-25 18:05, Stanis³aw Findeisen wrote:
    >
    >
    >
    > > Hi

    >
    > > I am trying to define an extern "C" friend function without external
    > > linkage. The idea is to pass this function to pthread_once and use it
    > > for initialization of a singleton object in a multithreaded program.

    >
    > > I don't want external linkage because I don't want other parts of the
    > > program to be able to call this initialization function.

    >
    > > Here is an example that does no pthread_once call but uses extern "C".
    > > The point, after all, is to have C linkage.

    >
    > > ========== MyClass.h BEGIN ==========
    > > #ifdef UGLY_UGLY_UGLY_MyClass_implementation_is_here
    > > extern "C" {
    > > static void changeX();
    > > }
    > > #endif

    >
    > > class MyClass {
    > > public:
    > > static void printX();
    > > private:
    > > friend void changeX();
    > > static int x;
    > > };

    >
    > > extern "C" void testChangeX();
    > > ========== MyClass.h END ============

    >
    > > ========== MyClass.cpp BEGIN ==========
    > > #include <iostream>
    > > #define UGLY_UGLY_UGLY_MyClass_implementation_is_here
    > > #include "MyClass.h"

    >
    > > int MyClass::x = 5;

    >
    > > void MyClass::printX() {
    > > std::cout << "x is now: " << x << std::endl;
    > > }

    >
    > > extern "C" void changeX() {
    > > MyClass::x = 7;
    > > }

    >
    > > extern "C" void testChangeX() {
    > > changeX();
    > > }
    > > ========== MyClass.cpp END ============

    >
    > > ========== test-friend.cpp BEGIN ============
    > > #include "MyClass.h"

    >
    > > int main() {
    > > MyClass::printX();
    > > changeX();
    > > testChangeX();
    > > MyClass::printX();

    >
    > > return 0;
    > > }
    > > ========== test-friend.cpp END ==============

    >
    > > ========== Makefile BEGIN ==============
    > > .PHONY: default
    > > default:
    > > g++ -Wall -c MyClass.cpp -o MyClass.o
    > > g++ -Wall -c test-friend.cpp -o test-friend.o
    > > g++ -Wall -o test-friend.out MyClass.o test-friend.o

    >
    > > .PHONY: clean
    > > clean:
    > > rm -f MyClass.o
    > > rm -f test-friend.o
    > > rm -f test-friend.out
    > > ========== Makefile END ==============

    >
    > > Here changeX is the secret initialization function, and testChangeX
    > > simulates pthreads library C code that changeX is called from
    > > (testChangeX has external linkage and that's no problem).

    >
    > > It *WORKS* here (the program does not compile until I delete changeX
    > > call from main()), but as you can see, this is quite ugly. The question
    > > is how to simplify this.

    >
    > > Explanation:

    >
    > > 1. changeX() declaration at the beginning of MyClass.h seems necessary,
    > > because without it my compiler complains:

    >
    > >> MyClass.h: In function 'void changeX()':
    > >> MyClass.h:11: error: previous declaration of 'void changeX()' with 'C++' linkage
    > >> MyClass.cpp:11: error: conflicts with new declaration with 'C' linkage

    >
    > > I think that's because of the Standard saying (11.4.3):

    >
    > >> A function first declared in a friend declaration has external linkage (3.5). Otherwise, the function retains its previous linkage (7.1.1).

    >
    > > 2. The ugly macro helps to fix the problem of other (than MyClass.cpp)
    > > translation units encountering the declaration of changeX in MyClass.h.
    > > Each such case generates a warning:

    >
    > >> MyClass.h:11: warning: 'void changeX()' declared 'static' but never defined

    >
    > > Sooo, does anyone has an idea how to simplify this? :)

    >
    > > You should be able to download the above source here:
    > >http://eisenbits.homelinux.net/~stf/load/20100825-friend-1.tgz.

    >
    > > I am using g++ for this:

    >
    > > g++ (Debian 4.3.2-1.1) 4.3.2
    > > Copyright (C) 2008 Free Software Foundation, Inc.
    > > This is free software; see the source for copying conditions. There is NO
    > > warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    >
    > > however I do care about POSIX compliance.

    >
    > Probably moving
    >
    > extern "C" {
    > static void changeX();
    >
    > }
    >
    > declaration to MyClass.cpp helps a bit...
    >
    > STF
    >
    > http://eisenbits.homelinux.net/~stf/
    > OpenPGP: DFD9 0146 3794 9CF6 17EA D63F DBF5 8AA8 3B31 FE8A


    Yeah. Also, possibly,

    namespace { extern "C" { static void changeX(); } }

    Goran.
     
    Goran Pusic, Aug 26, 2010
    #3
    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. usr2003
    Replies:
    4
    Views:
    604
    usr2003
    Sep 19, 2003
  2. Steve Kobes

    extern and linkage

    Steve Kobes, Jun 9, 2004, in forum: C Programming
    Replies:
    1
    Views:
    298
    Chris Torek
    Jun 9, 2004
  3. Ian
    Replies:
    22
    Views:
    1,006
  4. Mark A. Gibbs

    Static linkage and extern "C"

    Mark A. Gibbs, Oct 20, 2005, in forum: C++
    Replies:
    10
    Views:
    781
    Mark A. Gibbs
    Oct 21, 2005
  5. Replies:
    1
    Views:
    598
    Michael DOUBEZ
    Sep 12, 2008
Loading...

Share This Page