Multiple function definition in C / C ++ code

This is a question about C / C ++ function definitions. The code libRmath static library, which provides definitions in the Rmath.h header file in R

The documentation provided for the library states that it is not necessary for the user to provide a function definition for the double unif_rand(void) function.

So my question is whether such a function definition is optional, will there be a problem with many function definitions that are not valid in C/C++ ?

Edit: It may be tempting to talk about how everything works without looking at the source code, but that's not what I want. I am interested to know how it really works, so you probably need to read the source code and to answer this question.

+7
source share
2 answers

When the application is connected, unresolved characters will be resolved using the libraries you provide. If you do not define a function, it will be an unresolved symbol during binding, so the bound will try to resolve that symbol using librmath, in this case. If one or more characters cannot be resolved, you will receive a linker error.

However, if you define a function in your code, it will already be defined during linking, so there is no need to resolve it using characters from external libraries.

What you cannot do is identify the same character more than once in your application.

Change Since there is a lot of controversy in another answer, I made a practical example. I created a generic object (similar to a DLL on Windows) that defines and exports the foo function:

 //lib.h extern "C" { void foo(); void bar(); }; //lib.cpp #include <iostream> #include "lib.h" void foo() { std::cout << "From lib\n"; } void bar() { std::cout << "Bar, calling foo\n"; foo(); } 

To test this shared object, I created an application that is associated with it:

 //test.cpp #include <iostream> #include "lib.h" void foo() { std::cout << "From app\n"; } int main() { bar(); } 

I compiled both a generic object and an application:

 g++ lib.cpp -o libtest.so -Wall -fPIC -shared -Wl,--export-dynamic -Wl,-soname,libtest.so -Wl,-z,defs g++ test.cpp -o test -L. -ltest 

And when I execute test setting the library path to "." , so my shared object can be loaded, I get this output:

 matias@master :/tmp$ LD_LIBRARY_PATH="." ./test Bar, calling foo From app 

As you can see, the foo function defined in the application (and not the shared object) is called. You can basically do this for each exported character in a shared object.

EDIT2 : I added another exported function to lib.h. The application now calls this function, which ends with a call to foo. The result will be the same as expected.

EDIT3 : Alright, let go deeper. This is a dump from the bar function:

 Dump of assembler code for function bar@plt : 0x0804855c <+0>: jmp DWORD PTR ds:0x804a004 0x08048562 <+6>: push 0x8 0x08048567 <+11>: jmp 0x804853c 

If we get to address 0x804a004 :

 Dump of assembler code for function _GLOBAL_OFFSET_TABLE_: 0x08049ff4 <+0>: or BYTE PTR [edi+0x804],bl 0x08049ffa <+6>: add BYTE PTR [eax],al 0x08049ffc <+8>: add BYTE PTR [eax],al 0x08049ffe <+10>: add BYTE PTR [eax],al ..... 

As you can see, it jumps to the global offset table. You can read here GOT here and here . Dynamic characters (which are allowed at run time) are stored in this table. Whenever you call a character that must be allowed at run time, you actually go to this table, and then go to the address that is stored in that table of the corresponding record. Since the application defines foo , GOT contains the definition address from test.cpp , not the one that is in our shared object.

EDIT4 : Okay, last edit. Quoting from the documentation:

You will need to provide a single random number generator

  double unif_rand(void) 

or use one of them (and with a dynamic library or DLL you will have to use one supplied (...)

The documentation clearly states that you cannot provide your own unif_rand implementation if you use a dynamic library. Therefore, I believe that what I have indicated really answers your question.

+15
source

Linking a static library is slightly different than linking all objects within a static library.

Definitions in a static library are only inserted if necessary, so they cannot cause multiple definition errors.

This has some side effects, for example, the famous global initializers inside the static library do not start when nothing in the main program refers to this object.

0
source

All Articles