I have checked out the definition of std::ios::app in /usr/include/c++/4.6/bits/ios_base.h and found that std::ios::app is defined as a const static variable:
typedef _Ios_Openmode openmode;
/// Seek to end before each write.
static const openmode app = _S_app;
in which _Ios_Openmode is defined in the same header file as
enum _Ios_Openmode
{
_S_app = 1L << 0,
_S_ate = 1L << 1,
_S_bin = 1L << 2,
_S_in = 1L << 3,
_S_out = 1L << 4,
_S_trunc = 1L << 5,
_S_ios_openmode_end = 1L << 16
};
It's well known that static variable has internal linkage and every translation unit has its own
copy of this static variable, which means static variables in different translation unit should have different addresses. However, I have used two separate programs to print address of std::ios::app and found that the printed address are the same:
source file test1.cpp
#include <iostream>
int main() {
std::cout << "address: " << &std::ios::app << std::endl;
return 0;
}
result
address: 0x804a0cc
source file test2.cpp is the same with test1.cpp and the result is the same:
address: 0x804a0cc
This really confused me, shouldn't static variables in different translation units have different addresses?
Update: as is pointed out in the comments, std::ios::app is a static data member rather than a static const variable; static data member has external linkage and addresses of static data member in different translation unit should be the same. The second point is that my method for validating this fact is wrong: different program does not mean different translation unit.
Your test1.cpp
and test2.cpp
are not only two separate translation units, but you compile them into two entirely different programs and run them as separate processes. The memory space for each process is defined by the operating system anew each time you run it, and the absolute values of the addresses in each process cannot be compared. They may be identical even when you run the processes in parallel, because these addresses are interpreted relative to the virtual address space of each process. (*)
If you want to see the effect of internal linkage, you need to link the two translation units together after compiling them.
You can do this in the following way:
Define a header test.h
:
const static int i = 0;
Define the implementation of a function print_i_1
in test1.cpp
:
#include <iostream>
#include "test.h"
void print_i_1()
{ std::cout << &i << std::endl; }
Define the implementation of a function print_i_2
in test2.cpp
:
#include <iostream>
#include "test.h"
void print_i_2()
{ std::cout << &i << std::endl; }
Note that both functions perform the same operation, but as long as they are compiled separately, they will each refer to a different instance of i
.
Note also that none of these programs includes the definition of main()
. We provide this in a third file, test.cpp
:
extern void print_i_1();
extern void print_i_2();
int main()
{
print_i_1();
print_i_2();
return 0;
}
And now you compile each .cpp file (so we have three translation units). I am using GCC, but a similar thing is possible with other compilers, too:
g++ -W -Wall -g -o test1.o -c ./test1.cpp
g++ -W -Wall -g -o test2.o -c ./test2.cpp
g++ -W -Wall -g -o test.o -c ./test.cpp
And then link them together:
g++ -W -Wall -g -o test ./test.o ./test1.o ./test2.o
The output I get when running the resulting executable, test
, is:
0x4009c8
0x4009d0
Two different addresses.
Note that the keyword static
is not actually required in C++ to accomplish this for const
variables in namespace scope (including global namespace scope). They have internal linkage automatically, unless explicitly declared extern
.
(*) As it turns out, you seem to be using the address of a static member of a class defined in the standard library. In that case, there are two remarks to be made:
- If you link to the standard library dynamically, objects can actually be shared even between two separate processes (which, however, still does not necessarily mean that the addresses displayed will be the same, due to each process still having its own address space);
- However, static class members have external linkage, so your assumptions would have been wrong right from the start in this case.
9.4.2 defines the rules for static data members:
9.4.2/3 defines that a static const literal `can specify a brace-or-equal-initializer.' Meaning, that you can define it similar to X::x below.
9.4.2/4 defines that only one definition can exist (`one definition rule' (odr), see 3.2).
And finally, 9.4.2/5 further defines that all static data members of a class in namespace scope will have external linkage.
Example:
// test.h
struct X {
static const int x = 10;
};
// main.cpp
#include <iostream>
#include "test.h"
void f();
int main(int argc, const char* argv[]) {
std::cout << &X::x << std::endl;
f();
return 0;
}
// test.cpp
#include <iostream>
#include "test.h"
void f() {
std::cout << &X::x << std::endl;
}
Output:
001A31C4
001A31C4