extern "C" friend function without external linkage

  • Thread starter StanisÅ‚aw Findeisen
  • Start date
S

Stanisław Findeisen

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
 
S

Stanisław Findeisen

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:


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


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:


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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top