Reputation: 341
I have a header file foo.h
:
#ifndef __FOO_H__
#define __FOO_H__
const char* USB_MANAGER_DBUS_SERVICE = "com.USBService";
#define USB_MANAGER_DBUS_OBJ_PATH "/com/USB/MgrObject"
const int DBUS_CONNECTION_MAX_RETRY_TIME = 5;
#endif
And many cpp files that includes foo.h
.
foo.c bar.c
When compiling them together, "multiple definition error" appears.
Linking CXX shared library:
foo.cpp.o:(.data.rel.local+0x0): multiple definition of `USB_MANAGER_DBUS_SERVICE'
bar.cpp.o:(.data.rel.local+0x0): first defined here
So I have two questions below:
#define
lead to a link error?const int
lead to a link error?Upvotes: 2
Views: 1611
Reputation: 31435
const char* USB_MANAGER_DBUS_SERVICE = "com.USBService";
The string this pointer points to is const, but the pointer is not const, thus it is a multiple definition. Change it to
const char USB_MANAGER_DBUS_SERVICE[] = "com.USBService";
There is no linkage error for the const int because it is a real constant, not a const-modifier. It is therefore considered static
data to the application.
Incidentally if you put in another const for the pointer
const char* const USB_MANAGER_DBUS_SERVICE = "com.USBService";
Now that pointer is a proper constant too, but I'm not sure if it will work. You can declare it as extern
and then define it in one compilation unit, but the simplest is the first syntax I showed you.
Upvotes: 0
Reputation: 30605
The #define
for USB_MANAGER_DBUS_OBJ_PATH
is constant across compilation units, it is a text substitution.
So is the const int
for DBUS_CONNECTION_MAX_RETRY_TIME
constant across TU. The const
makes the variable read only, it's essentially not declaring it as a modifiable lvalue, it has an implicit internal linkage, from these posts.
const char* USB_MANAGER_DBUS_SERVICE = "com.USBService";
Why does USB_MANAGER_DBUS_SERVICE
cause a linker error?
It is not const
, as in the pointer is not a constant value, only what is being pointed to.
const char* const USB_MANAGER_DBUS_SERVICE = "com.USBService";
// ^^^^^ added const
Would be const
.
Upvotes: 5
Reputation: 7118
Here's the problem. By having #ifndef FOO_H wrapper, you are avoiding multiple inclusion of foo.h in your .c or .cpp file, but when linker links all different object files together, you have multiple definitions. Remedy is you use like the following in foo.h:
#ifndef __FOO_H__
#define __FOO_H__
extern const char* USB_MANAGER_DBUS_SERVICE;
#define USB_MANAGER_DBUS_OBJ_PATH "/com/USB/MgrObject"
extern const int DBUS_CONNECTION_MAX_RETRY_TIME;
#endif
And, in only one .c or .cpp file (i.e one source file), use the following: const char* USB_MANAGER_DBUS_SERVICE = "com.USBService"; const int DBUS_CONNECTION_MAX_RETRY_TIME = 5;
This will solve your multiple definition problem complained by the linker.
Upvotes: 0
Reputation: 821
"#define"d tokens are already processed by the preprocessor, even before the compiler comes into play.
In C++ and "const int" values are evaluated at compile time, i.e. a "const int" is equivalent to a typesafe define (and thus should be preferred over #define).
The only symbol the compiler actually creates for the linker is "USB_MANAGER_DBUS_SERVICE", because only the target to which the pointer points to is "const", but not the pointer itself.
Upvotes: 1
Reputation: 97948
Define doesn't cause a link error because the preprocessor is just pasting the string literal into different parts of the code instead of referring to some object defined in some object file.
const int
does not cause a link error because const
implies internal linkage, so you end up having a constant per compilation unit.
You can fix the redefinition error by defining extern const char* USB_MANAGER_DBUS_SERVICE;
in the header file and defining const char* USB_MANAGER_DBUS_SERVICE = "..."
in one of your source files.
Upvotes: 1