MESSAGE
DATE | 2010-02-13 |
FROM | Ruben Safir
|
SUBJECT | Subject: [NYLXS - HANGOUT] C++ Workshop - side discussing on C++ variable declarations
|
Date: Sat, 13 Feb 2010 20:43:04 -0500 From: Ruben Safir To: NYLUG Technical Discussion Subject: Re: [nylug-talk] C++ Workshop - side discussing on C++ variable declarations User-Agent: Mutt/1.5.20 (2009-06-14)
Alright - I'm top posting :)
Here is an example of the error that I had in mind, and you'll see how the linker behaves, although I thought I might get a different behavior.
http://www.nylxs.com/docs/workshops/scope/
First
The header file construction: scope.h
---
#ifndef SCOPETEST #define SCOPETEST #endif
using namespace std;
extern int global_i; int global_def; void test_obj(); void test_obj2(); ------
First Library File Construction: scope1.cc
----- #include "scope.h" #include
void test_obj(){ int global_i = 5; global_def = 200; cout << "Global Declared Variable ==>" << global_i << endl; cout << "Global defined Variable ==>" << global_def << endl; }
_______
Second Library Source File Construction: scope2.cc
______
#include "scope.h" #include
void test_obj2(){ int global_i = 5; global_def = 300; cout << "Global Declared Variable ==>" << global_i << endl; cout << "Global defined Variable ==>" << global_def << endl; }
________
The main programming file: scope_main.cc
----------- #include #include "scope.h"
using namespace std;
int main(int argv, char * argc[]){ int global_i = 25; // int global_def; cout << "Global Declare " << global_i << endl; cout << "Global Declare " << global_def << endl;
test_obj(); test_obj2(); return 0; }
____________
Not create a makefile that produces two seperate object files, one for each libary source file: makefile
_____________
scope : scope1.o scope2.o scope_main.o g++ -o scope scope_main.o scope1.o scope2.o
scope1.o : scope1.cc scope.h g++ -Wall -c scope1.cc
scope2.o : scope2.cc scope.h g++ -Wall -c scope2.cc
file5_main.o : scope_main.cc g++ -Wall -c scope_main.cc _____________
Now compile
ruben-at-www2:/usr/local/apache/htdocs/nylxs/docs/workshops/scope> make g++ -Wall -c scope1.cc g++ -Wall -c scope2.cc g++ -c -o scope_main.o scope_main.cc g++ -o scope scope_main.o scope1.o scope2.o scope1.o:(.bss+0x0): multiple definition of `global_def' scope_main.o:(.bss+0x0): first defined here scope2.o:(.bss+0x0): multiple definition of `global_def' scope_main.o:(.bss+0x0): first defined here collect2: ld returned 1 exit status make: *** [scope] Error 1
Lets look at that output individually
The compiler creates all the objects (3 of them in this case) without a problem:
g++ -Wall -c scope1.cc g++ -Wall -c scope2.cc g++ -c -o scope_main.o scope_main.cc
ruben-at-www2:/usr/local/apache/htdocs/nylxs/docs/workshops/scope> ls -al *o -rw-r--r-- 1 ruben users 2272 2010-02-13 19:52 scope1.o -rw-r--r-- 1 ruben users 2272 2010-02-13 19:52 scope2.o -rw-r--r-- 1 ruben users 2312 2010-02-13 19:52 scope_main.o
ruben-at-www2:/usr/local/apache/htdocs/nylxs/docs/workshops/scope> nm scope1.o 000000c7 t _GLOBAL__I_global_def 00000087 t _Z41__static_initialization_and_destruction_0ii 00000000 T _Z8test_objv U _ZNSolsEPFRSoS_E U _ZNSolsEi U _ZNSt8ios_base4InitC1Ev U _ZNSt8ios_base4InitD1Ev U _ZSt4cout U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ 00000004 b _ZStL8__ioinit U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc U __cxa_atexit U __dso_handle U __gxx_personality_v0 00000000 B global_def
ruben-at-www2:/usr/local/apache/htdocs/nylxs/docs/workshops/scope> nm scope2.o 000000c7 t _GLOBAL__I_global_def 00000087 t _Z41__static_initialization_and_destruction_0ii 00000000 T _Z9test_obj2v U _ZNSolsEPFRSoS_E U _ZNSolsEi U _ZNSt8ios_base4InitC1Ev U _ZNSt8ios_base4InitD1Ev U _ZSt4cout U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ 00000004 b _ZStL8__ioinit U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc U __cxa_atexit U __dso_handle U __gxx_personality_v0 00000000 B global_def
ruben-at-www2:/usr/local/apache/htdocs/nylxs/docs/workshops/scope> nm scope_main.o 000000d3 t _GLOBAL__I_global_def 00000093 t _Z41__static_initialization_and_destruction_0ii U _Z8test_objv U _Z9test_obj2v U _ZNSolsEPFRSoS_E U _ZNSolsEi U _ZNSt8ios_base4InitC1Ev U _ZNSt8ios_base4InitD1Ev U _ZSt4cout U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ 00000004 b _ZStL8__ioinit U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc U __cxa_atexit U __dso_handle U __gxx_personality_v0 00000000 B global_def 00000000 T main
Here you can see that all three ojects made room for the symbol global_def. I just don't know what the left colomn means, and the man page for nm is not helpful.
On Fri, Feb 12, 2010 at 11:35:23AM -0500, Chris Knadle wrote: > On Friday 12 February 2010 03:00:23 Chris Knadle wrote: > > On Thursday 11 February 2010 19:24:44 Ruben Safir wrote: > > > On Thu, Feb 11, 2010 at 07:01:11PM -0500, Ajai Khattri wrote: > > > > On Thu, 11 Feb 2010, Ruben Safir wrote: > > > > > Anyone have any constructive insight on this conversation I had with > > > > > a friend? > > > > > > > > I dont see what the problem is. If you're linking to code that is > > > > outside the current file you must tell the compiler that it is defined > > > > EXTERNally. > > > > > > > > Often when your code is spread across several files, you might want to > > > > refer to symbols defined in other files or other libraries, so you must > > > > declare them ahead of your code. > > > > > > Its the idea that if you define the var (that is, not use the extern > > > keyword), that it can create a problem that is bothering me and getting > > > under my skin. > > I've created a C++ program to illustrate, as well as to test the way I thought > this worked. > > //================================== > //file extern_test_1.cpp > > #include > > using namespace std; > > int global_var=0; > void external_increment(void); // extern funct to increment global_var by 1 > > void local_increment_10(void) > { > global_var += 10; > cout << global_var << "\t after +10 locally" << endl; > } > > int main(void) > { > for (int x=0; x<4; x++) { > local_increment_10(); // global_var += 10 > external_increment(); // global_var += 1 > external_increment(); // global_var += 1 > } > cout << "ending global_var: " << global_var << endl; > return 0; > } > //================================== > > > > //================================== > // file extern_test_2.cpp > > #include > > using namespace std; > > extern int global_var; > > void external_increment(void) > { > global_var += 1; > cout << global_var << " \t after +1 externally" << endl; > } > //================================== > > > > Compiled via the command: > g++ extern_test_1.cpp extern_test_2.cpp -o extern_test > > > > Notes: > - Leaving out the 'extern' keyword in extern_test_2.cpp causes > a compile error. (This is a good thing!) > > - In the function prototype for external_increment() in > extern_test_1.cpp I didn't add the 'extern' keyword because I > wanted to demonstrate that for functions (only) the 'extern' > keyword is optional in C++, but it should /should/ be added > there for human readability. The compiler may be able to > figure out the function is external, but I wouldn't want to > have to... > > - Global variables should be avoided where possible > > -- Chris > > -- > > Chris Knadle > Chris.Knadle-at-coredump.us
--
|
|