The way C++ handles global
const
variables is different from C. In C++, a global const variable that is not explicitly declared
extern
has static linkage.In C, global const variables will have
extern
linkage by default, and global variables can be declared more than once. As long as a single initialization (at most) for the same variable is used, the linker resolves all the repeated declarations into a single entity; and the the initialization takes place when the program starts up, before entry to the main function.This can be illustrated with a simple C program, that produces different results when compiled with C and C++ compilers
% cat mylib.h
const float libraryversion = 2.2;
float getlibversion();
int checklibversion();
% cat mylib.c
#include <stdio.h>
#include "mylib.h"
float getlibversion() {
printf("\nmylib.c: libraryversion = %f", libraryversion);
return (libraryversion);
}
int checklibversion() {
float ver;
ver = getlibversion();
printf("\nmylib.c: ver = %f", ver);
if (ver < 2.0) {
return (1);
} else {
return (0);
}
}
% cat thirdpartylib.h
extern const float libraryversion = 1.5;
float getlibversion();
% cat thirdpartylib.c
#include <stdio.h>
#include "thirdpartylib.h"
float getlibversion() {
printf("\nthirdparty.c: libraryversion = %f", libraryversion);
return (libraryversion);
}
% cat versioncheck.c
#include <stdio.h>
#include "mylib.h"
int main() {
printf("\n** versioncheck.c: libraryversion = %f", libraryversion);
int retval = 0;
retval = checklibversion();
if (retval) {
printf("\n** Obsolete version being used .. Can\'t proceed further! **\n");
} else {
printf("\n** Met the library version requirement .. Good to Go! ** \n");
}
return (0);
}
Case 1:
Compile with Sun Studio C compiler:
% cc -G -o libmylib.so mylib.c
% cc -G -o libthirdparty.so thirdpartylib.c
% cc -o vercheck -lthirdparty -lmylib versioncheck.c
% ./vercheck
** versioncheck.c: libraryversion = 2.200000
thirdparty.c: libraryversion = 2.200000
mylib.c: ver = 2.200000
** Met the library version requirement .. Good to Go! **
From this output, it appears that it is working as expected although there is a symbol collision between
libmylib
and libthirdparty
load modules over libraryversion
symbol.Case 2:
Compile with Sun Studio C++ compiler:
% CC -G -o libmylib.so mylib.c
% CC -G -o libthirdparty.so thirdpartylib.c
% CC -o vercheck -lthirdparty -lmylib versioncheck.c
% ./vercheck
** versioncheck.c: libraryversion = 2.200000
thirdparty.c: libraryversion = 1.500000
mylib.c: ver = 1.500000
** Obsolete version being used .. Can't proceed further! **
The inherent symbol collision was exposed when the code was compiled with C++ compiler.
It is a known fact that the global
const
variables, as libraryversion
in this example are bound to cause problems.The following is an alternative implementation of the above example, which shows consistent behavior when compiled with C and C++ compilers.
% cat mylib_public.h
float getlibversion();
int checklibversion();
% cat mylib_private.h
#include "mylib_public.h"
const float libversion = 2.2;
% cat mylib.c
#include <stdio.h>
#include "mylib_private.h"
float getlibversion() {
printf("\nmylib.c: libraryversion = %f", libraryversion);
return (libraryversion);
}
int checklibversion() {
float ver;
ver = getlibversion();
printf("\nmylib.c: ver = %f", ver);
if (ver < 2.0) {
return (1);
} else {
return (0);
}
}
% cat versioncheck.c
#include <stdio.h>
#include "mylib_public.h"
int main() {
int retval = 0;
retval = checklibversion();
if (retval) {
printf("\n** Obsolete version being used .. Can\'t proceed further! **\n");
} else {
printf("\n** Met the library version requirement .. Good to Go! ** \n");
}
return (0);
}
Since we cannot control 3rd party implementation, it was kept intact in this example.
Case 1:
Compile with Sun Studio C compiler:
% cc -G -o libmylib.so mylib.c
% cc -G -o libthirdparty.so thirdpartylib.c
% cc -o vercheck -lthirdparty -lmylib versioncheck.c
% ./vercheck
thirdparty.c: libraryversion = 1.500000
mylib.c: ver = 1.500000
** Obsolete version being used .. Can't proceed further! **
Case 2:
Compile with Sun Studio C++ compiler:
% CC -G -o libmylib.so mylib.c
% CC -G -o libthirdparty.so thirdpartylib.c
% CC -o vercheck -lthirdparty -lmylib versioncheck.c
% ./vercheck
thirdparty.c: libraryversion = 1.500000
mylib.c: ver = 1.500000
** Obsolete version being used .. Can't proceed further! **
Now with the new implementation, the behavior of the code is the same and as expected with both C and C++ compilers.
The final paragraph proposes a solution common to both C and C++, to resolve the symbol collision. With C++, symbol collisions can be minimized using namespaces.
symbolic (protected) scope
All symbols of a library get symbolic scope, when the library was built with Sun Studio's
-xldscope=symbolic
compiler option.Symbolic scoping is more restrictive than global linker scoping; all references within a library that match definitions within the library will bind to those definitions. Outside of the library, the symbol appears as though it was global. That is, at first the link-editor tries to find the definition of the symbol being used in the same shared library. If found the symbol will be bound to the definition during link time; otherwise the search continues outside the library as the case with global symbols. This explanation holds good for functions, but for variables, there is an extra complication of copy relocations.
Let's see how symbolic scope works practically, by compiling the same code again with
-xldscope=symbolic
option.Case 1:
Compile with Sun Studio C compiler:
% cc -G -o libmylib.so -xldscope=symbolic mylib.c
% cc -G -o libthirdparty.so thirdpartylib.c
% cc -o vercheck -lthirdparty -lmylib versioncheck.c
% ./vercheck
mylib.c: libraryversion = 2.200000
mylib.c: ver = 2.200000
** Met the library version requirement .. Good to Go! **
Case 2:
Compile with Sun Studio C++ compiler:
% CC -G -o libmylib.so -xldscope=symbolic mylib.c
% CC -G -o libthirdparty.so thirdpartylib.c
% CC -o vercheck -lthirdparty -lmylib versioncheck.c
% ./vercheck
mylib.c: libraryversion = 2.200000
mylib.c: ver = 2.200000
** Met the library version requirement .. Good to Go! **
With symbolic (protected) scoping, the reference to the symbol
libraryversion
was bound to its definition within the load module libmylib
and the program showed the intended behavior.However the main drawback of
-xldscope=symbolic
is that, it may interpose the implementation symbols of C++. These implementation interfaces often must remain global within a group of similar dynamic objects, as one interface must interpose on all the others for the correct execution of the application. Due to this, the use of -xldscope=symbolic
is strongly discouraged. Sun Studio compilers (8 or later versions) provide a declaration specifier called
__symbolic
and using __symbolic
specifier with symbols that needs to have symbolic scope (protected symbols) is recommended.
No comments:
Post a Comment