Linker warnings when using extern reference to a pointer-to-function - c++

Api.cpp:
int (*theFunc) (int);
theFunc = (int (*) (int)) DlSym(hSo, "theFunc");
So far so good.
Now, I want to make a header so that other cpp files can also call theFunc.
Api.h: per How to declare function pointer in header and c-file?
extern int (*theFunc)(int);
/usr/bin/ld: Warning: type of symbol `theFunc' changed from 2 to 1 in Api.o
OK, so this is a warning that theFunc is seen as a function from one compilation element and as a variable in another. (Reference) This seems like bad things will happen at runtime.
This seems to be a proper declaration, what am I doing wrong?
Edit: Actually running in linux, so use DlSym not Microsoft GetProcAddress() call

According to the linked post, condense it to one line, not two in the .cpp file. So the .h seems right, and put this in the .cpp file:
int (*theFunc) (int) = (int (*) (int)) GetProcAddress(hDll, "theFunc");
You're not doing declaration and assignment in one shot like the linked answer is. With what I posted above, you will be.

You probably should not include Api.h
Alternatively you may work with macros in a way that api.h behave somewhat different when included by api.cpp.
MicroSoft has done/do such things.
api.h
#ifdef _API_
#define EXTERN
#else
#define EXTERN extern
#endif
EXTERN int (*theFunc)(int);
api.cpp
#define _API_
#include "api.h"
...
other.cpp
#define _OTHER_
#include "api.h"
...

Related

Alias a function in a different source file

I've got a .h file and three .cpp files. All cpp files include the .h file.
I want to create a useless function in one of the cpp files and use alias in the other cpp files to refere to this useless function. But if i move the function from important.cpp to useless.cpp it does not want to compile anymore. For some reason it doesnt see the function, even if its declared in the header.
useless.h
#ifdef __cplusplus
extern "C" {
#endif
extern void useless(void);
#ifdef __cplusplus
}
#endif
useless.cpp
#ifdef __cplusplus
extern "C" {
#endif
void useless(void) { }
#ifdef __cplusplus
}
#endif
important.cpp
void important(void) __attribute__((alias("useless")));
error: 'void important()' aliased to undefined symbol 'useless'
void important(void) attribute((alias("useless")));
Why are you using a bunch of extern "C" stuff?
If it's a C++ project and a global C++ function, you really should claim it's a C function. Doing so can lead to undefined reference-type errors, as the symbol names are different for C and C++.
What you're trying to do is probably impossible. Take a look at gcc docs https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html It says:
It is an error if ‘__f’ is not defined in the same translation unit.
So if you remove useless from the translation unit where important is it looks like an error to me.

Why am I getting linking errors even with header guards? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why does this not prevent multiple function declarations?
Global.h
#ifndef Global_h
#define Global_h
#include <iostream>
unsigned char exitStatus;
#endif
OutputHandler.h
#ifndef OutputHandler_h
#define OutputHandler_h
#include "Global.h"
class OutputHandler {
private:
static bool instanceExists;
// more code
#endif
Root.h
#ifndef Root_h
#define Root_h
// declarations
OutputHandler *output;
#endif
Root.cpp
#include "Root.h"
// gets instance of OutputHandler
// more code
I am getting errors regarding exitStatus, static bool instanceExists, and static class output being already defined by Root.obj in OutputHandler.obj. I assume the issue is with including the header file OutputHandler.h in both Root.h and OutputHandler.cpp. Anyone know how to fix this or how to better organize header files?
Because include guards only work at the translation unit level (you can, for this simple case, consider a single C file to be a translation unit).
That means a single C file, if it includes the header file twice, will not process it the second time due to the include guards.
However, if you include the header from two different C files, each of them will get a copy of the variables defined in that header.
Then, when you link them together, you get the duplicates.
The easiest way to get around this problem is to never define things in headers, only declare them.
So, in the header (eg, xyzzy.h), you have:
extern int xyzzy; // declare but don't define.
and in all the C files that want to use that, put:
$include "xyzzy.h"
and, in one of those C files, also put:
int xyzzy; // define it here, once.
You can think of declaration as a simple "I declare that this exists somewhere, just not here", while definition is "I an creating this here and now".
Declare extern usigned char exitStatus in Global.h and define it in one implementation file.
The problem is during the linking phase; include guards in the headers won't help you.
In C, there is the separate concepts of declarations and definitions. Declarations are what are put into headers; they merely state that a particular variable exists. The definition of a variable is where storage is actually allocated for it.
For example, in your Global.h, you have:
#ifndef Global_h
#define Global_h
#include <iostream>
usigned char exitStatus;
#endif
This is defining a variable called exitStatus, and the linker is complaining because any given variable should only be defined in one place in a program. What you need to do is declare it in the header, and then define it in only one place in a source (*.cpp) file. For example, your header should declare exitStatus with:
extern char exitStatus;
and in only one source file, define it with:
char exitStatus;
The situation is similar for output in Root.h, as well as any other place you should be declaring variables in the header file.
See also: http://www.cprogramming.com/declare_vs_define.html

C++ variable shared by 2 files

I have 4 files:
shared.h
main.cpp
something.h
something.cpp
shared.h:
#ifndef SHARED_H
#define SHARED_H
int* sth;
#endif
something.h:
#ifndef SOMETHING_H
#define SOMETHING_H
class foo
{
public:
void printVar();
};
#endif
something.cpp:
#include <iostream>
#include "something.h"
#include "shared.h"
using namespace std;
void foo::printVar()
{
cout<<"Foo: "<<*sth<<endl;
};
main.cpp:
#include <cstdlib>
#include <iostream>
#include "shared.h"
#include "something.h"
using namespace std;
int main(int argc, char *argv[])
{
sth=new int(32);
foo x;
cout<<"Main: "<<*sth<<endl;
x.printVar();
system("PAUSE");
return EXIT_SUCCESS;
}
Compiler returns multipe definition of *sth;
I added static modifier to the *sth and it compiles, but crashes. I changed the printings to print the adresses of pointer and I had program returned:
Main: 0x3e0f20
Foo: 0
Why is the foo's pointer not assigned? I want to assign it only once in main and then share in other files... How can I do this? Is it something with extern modifier?
Thanx for any replies.
In shared.h you want to say:
extern int* sth;
to promise the compiler that sth exists somewhere.
Then in one (and only one) of the .cpp files you need to write:
int* sth;
To make it actually exists. In general you probably want to read about the difference between declaration and definition. As a rule of thumb you only want to declare things in header files, not define them.
When you wrote static previously you said that a variable with the same name exists in every file, but is "local" to each, i.e. the sth in main.cpp won't be the same as the sth in something.cpp.
Yes, use extern. Put extern int* sth; in the header, and then in one of the source files put int* sth;.
extern tells the compiler and linker that the actual variable/function definition is in another compilation unit (i.e. another source file).
You need to mark sth as extern in the header to make it a declaration, and provide a definition for it in one of the cpp files. Otherwise, the variable is declared in each compilation unit where the header is included, which is not the effect you are looking for.
P.S. I assume that you know why global variables are not good, right?
"I have 4 files".
Let me stop you right there. I agree that you have four files, but that's not really relevant. You have two translation units. A translation unit is the quantum of text that is fed into your compiler. Your translation units, let's call them MAIN and SOMETHING, consist of the result of preprocessing your files main.cpp and something.cpp, respectively.
After preprocessing, each of your translation units includes a line int *sth; This line declares and defines the variable sth.
The one-definition-rule requires that you have, in your entire program, exactly one (not more, not fewer) definition of sth. In order to accomplish this, you must have exactly one source-code line int *sth; in exactly one translation unit, and as many extern int *sth; as you require.
In your case, I would put int *sth; in MAIN and extern int *sth; in SOMETHING. Additionally, you can have as many extra copies of extern int *sth; as you feel like -- they won't hurt anything.
Now, back to your four files. You should put extern int *sth; in shared.h. This means that MAIN and SOMETHING will both have an extern line in them. You should also put int *sth; in main.cpp, so that MAIN will have the definition.
And there you are: MAIN and SOMETHING both have extern lines, so they are both referring to the same variable. MAIN also has a definition. so the sth variable has exactly one of those.
Aside: Why does static int *sth; in shared.h do the wrong thing?
Because each of the two translation units see their own static declaration. A static declaration reduces the linkage of the declared name to that single translation unit.
You don't want to make it a static global as that will create a local sth in every translation unit and you are only allocating it in one. This is why it crashed in Foo::printVar as in that scope it was an uninitialized pointer.
You want to declare it as extern int* sth; in the shared header then put int* sth; before main or in at least one place before it's used.
Actually, if you really need a globally accessible object, allocated on the heap, and you want to share it then it may be better as extern std::shared_ptr<int> sth;. Define it as std::shared_ptr<int> sth; the same way in one of the CPP files and call std::make_shared to allocate it. This way deallocating the memory will be handled automatically when the last object that uses it goes out of scope.

#ifndef not working as expected

Getting a LNK2005 "already defined in GUI.obj" for a function pointer in PAL.h
//GUI.cpp
#include "PAL.h"
//PAL.h
#define PAL_INCLUDE
int (*addPAL)( int, void(*)(), void(*)() );
//main.cpp
#include "GUI.h"
#ifndef PAL_INCLUDE
#include "PAL.h"
#endif
Have I misunderstood the nature of includes and #ifndef?
You're getting the error probably because the preprocessor is processing main.cpp before GUI.cpp.
Try changing the content of your PAL.h to this:
#ifndef PAL_INCLUDED
#define PAL_INCLUDED
// definitions
#endif
Reference
Include guard
I think you should use the include guard over PAL.h.
If I understand what you're trying to do, this code is much more clear (and quite common out there):
GUI.h
#ifndef _GUI_H_
#define _GUI_H_
...
#endif
GUI.cpp
#include "PAL.h"
...
PAL.h
#ifndef _PAL_H_
#define _PAL_H_
int (*addPAL)( int, void(*)(), void(*)() );
#endif
main.cpp
#include "GUI.h"
#include "PAL.h"
...
Hope it helps.
Main.cpp and GUI.cpp are compiled separately from each other and then linked together. This means the preprocessor state is reset between the two compiles, and you lose the definition of PAL_INCLUDE
Header guards stop a header from being included more than once by other headers in the same compile unit, not to prevent clashes in the linker.
Try putting static in front of the method declaration - it limits the function to the current unit, thus preventing this problem.
For more information, see What is a “static” function?
addPal is getting defined twice, once in GUI.cpp and once in main.cpp. What you want is to define it once and declare it everywhere you need to use it. I suggest putting
int (*addPAL)( int, void(*)(), void(*)() );
in one of the .cpp files (I haven't seen enough code to decide which one it belongs in), then the declaration:
extern int (*addPAL)( int, void(*)(), void(*)() );
in the header file. The extern tells the compiler that the pointer addPAL exists, but is defined elsewhere

global extern const clarification

Is declaring extern const or just extern the same thing in a header file? Also will both give external linkage?
globals.cpp
#include <string>
extern const std::string foo = "bar";
globals.h
#ifndef GLOBALS_H
#define GLOBALS_H
#include <iostream>
extern const std::string foo;
#endif /* GLOBALS_H */
OR
globals.h
#ifndef GLOBALS_H
#define GLOBALS_H
#include <iostream>
extern std::string foo;
#endif /* GLOBALS_H */
Both compiles and run fine, both give same address when used in multiple files, which one is more correct?
This one is correct,
//globals.h
extern const std::string foo; //Consistent
Consistent!
The correct one is
extern const std::string foo;
foo is a constant string in the source file it is defined in, so the extern declaration should indicate this too and allow the compiler to catch instances where code within source file where that header is included may try to modify foo.
The only reason they both compile fine is that you are not actually using foo, so it doesn't matter whether the linker can find foo or not (it never tries to). (Or your compiler/linker is rubbish. :) )
The consistent header is fine. The one missing the const is not and will/should result in errors if something tries to use foo.
If you make some file (not globals.cpp) which includes globals.h and tries to use foo (e.g. just add a line with "foo.c_str();" into a function) then you'll get a link error because no const std::string foo could be found.
This is how it has to be, too. The header is telling anything that wants to use foo that it can only read it, not modify it. Things which include the globals.h header have no idea of what is inside globals.cpp; if you want them to treat an object as const you have to put that information in a file which they include.
You can give const external linkage, as in your example, but it's still non-modifiable (constant).
P.S. you need to include <string>, not <iostream>
P.P.S. If I wasn't clear, you can't redefine const-ness. This will not compile:
extern std::string foo;
extern const std::string foo = "bar";
For C language, declare actual const in a .c file and use 'extern' for it in a header (.h) file. This should be as usual as we do when declaring a global variable.