Consider a C++ header file compiled both in my_lib.a and in my_prog that links with my_lib.a. The library was compiled without NDEBUG, while my_prog - with NDEBUG. Would it result in ODR violation?
What if my_lib.so is a shared library? Of course, ODR is irrelevant here, because there are 2 separate executables, but could NDEBUG affect std (or other) classes in a way that would prevent passing their instances correctly via SO interface? E.g. if an std::vector instance was created in my_prog, can it be passed as an argument to the SO? May NDEBUG affect memory allocation etc?
Does the Standard specify this?
20.5.2.2 Headers [using.headers]
A translation unit may include library headers in any order (Clause 5). Each may be included more than once, with no effect different from being included exactly once, except that the effect of including either <cassert> or <assert.h> depends each time on the lexically current definition of NDEBUG.
It is guaranteed not to be an issue for standard headers, however the issue you have highlighted does apply to functions in source files you provide yourself.
6.2 One-definition rule [basic.def.odr]
There can be more than one definition of a class [function/enum/variable/etc] provided the definitions satisfy the following requirements:
[...]
each definition of D shall consist of the same sequence of tokens;
Note that tokenisation happens after preprocessing, so if the definition contains any assert, this must preprocess to the same token sequence, i.e. must have the same NEDBUG setting during compilation.
Related
I am trying to a make plugin system which will have a header file for all plugins to include. In that header the version of the plugin system is defined in a #define like so:
PluginHeader.hpp:
#define PLUGIN_SYSTEM_VERSION "00.001"
class PluginSystem
{
public:
string GetSystemVersion(){return PLUGIN_SYSTEM_VERSION; }
void MyPluginDoStuff(){...}
}
I compile my plugin with this header in a dll and export it. Afterwards, i import it in the main application and i change the value of the #define in the calling application to be "00.002". If i call the method GetSystemVersion in the dll, then i am getting the new value "00.002".
Is this the expected behavior? How can i make the dll keep its defined value?
It is neither expected nor unexpected behaviour. Your program has undefined behaviour, so any outcome (whether it seems "right" or not) is possible.
Your member function PluginSystem::GetSystemVersion() is defined (implemented) within its class definition, so is implicitly inline.
The problem is, by having different definitions of the macro PLUGIN_SYSTEM_VERSION in different compilation units (e.g. in your DLL and in a separate source file that includes your header), you cause your program to have multiple definitions of PluginSystem::GetSystemVersion() (and, in fact, the whole class PluginSystem) in your program. If those definitions aren't exactly the same, you're breaking the one-definition rule. Which for an inlined function (and for a class) means that all definitions seen by different source files must be identical.
Breaking the one-definition rule means your program has undefined behaviour. Seeing different versions of an inline function being called in different compilation units (e.g. the DLL version called in some situations but not others) is one possible symptom of that.
If you want to have the function in the DLL, then
Change the class definition so that the function is not inline within the class definition, and ensure that class definition is used consistently everywhere (both in all source files for your program, and in all source files for the DLL) - for example, by including the same header everywhere it is needed;
In exactly one source file, for the DLL, include exactly ONE definition of the function outside the class definition.
Although not technically necessary, I'd encourage you to avoid using macros (other than include guards) in the header (or, even, using a macro for it at all - there are alternatives). If you must have a macro PLUGIN_SYSTEM_VERSION, define it locally to the single source file that defines PluginSystem::GetSystemVersion(). That avoids the possibility of confusing yourself (and increasing chances of getting unexpected behaviours) by having different incantations of PLUGIN_SYSTEM_VERSION (and code affected by it) in different parts of your program.
inline functions provide something of a weakening of the one definition rule -- multiple definitions are allowed, albeit with some restrictions. One wording I found online is
The requirements are that each definition should be the same, meaning it should consist of the same tokens and refer to the same items.
though I admit that I don't know if that's definitive. I'm also not sure how strict it is.
I'm considering cases in which I create headers with class definitions and/or inline functions that I want to be #include-able whether one is compiling in C++03, C++11, or even some later standard. It would be natural to use the __cplusplus macro to conditionally change the code, but will the ODR come into play? For example, it seems reasonable to conditionally:
provide a nested typedef.
provide a nested class.
provide move-related functions.
mark a function throw() or noexcept. (This is particularly important since every destructor picks up an implicit noexcept in C++11.)
mark a function constexpr.
mark a function with override and/or final.
mark a function [[noreturn]] and/or [[nodiscard]].
mark a parameter [[maybe_unused]].
use [[fallthrough]] within a function body.
but which of these -- if any -- are actually allowed if one wants to enable libraries that #include such headers to be compiled under different standards and still be safely used together?
In general, you can't do any of this stuff safely. There's only two ways to safely use say two definitions of a class. Trivially you can simply have two separate processes compiled differently that communicate via e.g. shared memory. Less trivially, you can use two libraries that define the same symbol A in two different way if:
the symbol A is only an implementation detail of the library; it cannot be provided by the library nor appear in any interfaces
Along these lines, none of the library's header files should transitively include A's header. So client translation units will not receive any definition of A from the library.
the visibility of the symbol A must be marked private/hidden.
If you do all that, then A is truly an implementation detail of the library, and you can use multiple libraries that define A differently. If any of these is not satisfied, then you can't guarantee that any of the above will work (though some will).
One of the most surprising outcomes for those not familiar with the linker, is that if lib1 and lib2 both use symbol A, even if they stop any leakage through the headers, if the visibility of A is public then a single definition of A will be used across both libraries. So either lib2 will use lib1's definition, or vice versa. This can rather easily lead to UB.
On *nix systems, public visibilility is the default so you will need to be sure to go out of your way to hide the symbol, which is a bit arcane.
When using __DATE__ or __TIME__ in a header file, the results of the preprocessor for that header inclusion can be somewhat different.
Under which circumstances does using __DATE__ or __TIME__ in a header file violate the one-definition-rule?
As a follow-up: Does the assert header violate the one-definition-rule?
If __TIME__ gives different results for different translation units, then it must not be used in a context where the same result is required across translation units. This means e.g. initialising an object (e.g. a class member) to __TIME__, where that initialiser is part of a header that gets included in multiple translation units, is going to be problematic.
__DATE__ is less likely to give different results for different translation units if you start a fresh build, but incremental builds, ones that only recompile the files that changed, do make it likely to become a problem as well.
assert is a macro that expands differently depending on how NDEBUG was defined when its header was included, so either the whole project must agree on whether NDEBUG should be defined, or functions defined in headers should avoid using assert.
The one definition rule is only applicable to variables, functions, class types, enumerations, or templates (e.g. Section 3.2, ISO/IEC 14882, 1998 C++ Standard). __DATE__ or __TIME__ are both predefined macros that expand to a string literal - which is not one of the things that the one-definition rule is applicable to.
assert() is also a preprocessor macro. If its expansion defines a variable, function, class type, enumeration, or template, then its use could potentially violate the one-definition rule, if that definition differed between translation units. Pragmatically, it is difficult to envisage a situation in which an implementation would have an assert() macro that expanded to such a definition.
After reading this question I thought I understood everything, but then I saw this file from a popular header-only library.
The library uses the #ifndef line, but the SO question points out that this is NOT adequate protection against multiple definition errors in multiple TUs.
So one of the following must be true:
It is possible to avoid multiple definition linker errors in ways other than described in the SO question. Perhaps the library is using techniques not mentioned in to the other SO question that are worthy of additional explanation.
The library assumes you won't include its header files in more than translation unit -- this seems fragile since a robust library shouldn't make this assumption on its users.
I'd appreciate having some light shed on this seemingly simple curiosity.
A header that causes linking problems when included in multiple translation units is one that will (attempt to) define some object (not just, for an obvious example, a type) in each source file where it's included.
For example, if you had something like: int f = 0; in a header, then each source file into which it was included would attempt to define f, and when you tried to link the object files together you'd get a complaint about multiple definitions of f.
The "technique" used in this header is simple: it doesn't attempt to define any actual objects. Rather, it includes some typedefs, and the definition of one fairly large class--but not any instances of that class or any instance of anything else either. That class includes a number of member functions, but they're all defined inside the function definition, which implicitly defines them as inline functions (so defining separately in each translation unit in which they're used is not only allowed, but required).
In short, the header only defines types, not objects, so there's nothing there to cause linker collisions when it's included in multiple source files that are linked together.
If the header defines items, as opposed to just declaring them, then it's possible to include it in more than one translation unit (i.e. cpp file) and have multiple definitions and hence linker errors.
I've used boost's unit test framework which is header only. I include a specified header in only one of my own cpp files to get my project to compile. But I include other unit test headers in other cpp files which presumably use the items that are defined in the specified header.
Headers only include libraries like Boost C++ Libraries use (mostly) stand-alone templates and as so are compiled at compile-time and don't require any linkage to binary libraries (that would need separate compilation). One designed to never need linkage is the great Catch
Templates are a special case in C++ regarding multiple definitions, as long as they're the same. See the "One Definition Rule" section of the C++ standard:
There can be more than one definition of a class type (Clause 9),
enumeration type (7.2), inline function with external linkage (7.1.2),
class template (Clause 14), non-static function template (14.5.6),
static data member of a class template (14.5.1.3), member function of
a class template (14.5.1.1), or template specialization for which some
template parameters are not specified (14.7, 14.5.5) in a program
provided that each definition appears in a different translation unit,
and provided the definitions satisfy the following requirements. ....
This is then followed by a list of conditions that make sure the template definitions are identical across translation units.
This specific quote is from the 2014 working draft, section 3.2 ("One Definition Rule"), subsection 6.
This header file can indeed be included in difference source files without causing "multiple symbol definition" errors.
This happens because it is fine to have multiple identically named symbols in different object files as long as these symbols are either weak or local.
Let's take a closer look at the header file. It (potentially) defines several objects like this helper:
static int const helper[] = {0,7,8,13};
Each translation unit that includes this header file will have this helper in it. However, there will be no "multiple symbol definition" errors, since helper is static and thus has internal linkage. The symbols created for helpers will be local and linker will just happily put them all in the resulting executable.
The header file also defines a class template connection. But it is also okay. Class templates can be defined multiple times in different translation units.
In fact, even regular class types can be defined multiple times (I've noticed that you've asked about this in the comments). Symbols created for member functions are usually weak symbols. Once again, weak symbols don't cause "multiple symbol definition" errors, because they can be redefined. Linker will just keep redefining weak symbols with names he has already seen until there will be just one symbol per member function left.
There are also other cases, where certain things (like inline functions and enumerations) can be defined several times in different translation units (see ยง3.2). And mechanisms of achieving this can be different (see class templates and inline functions). But the general rule is not to place stuff with global linkage in header files. As long as you follow this rule, you're really unlikely to stumble upon multiple symbol definitions problems.
And yes, include guards have nothing to do with this.
Many C++ projects (e.g. many Boost libraries) are "header-only linked".
Is this possible also in plain C? How to put the source code into headers? Are there any sites about it?
Executive summary: You can, but you shouldn't.
C and C++ code is preprocessed before it's compiled: all headers are "pasted" into the source files that include them, recursively. If you define a function in a header and it is included by two C files, you will end up with two copies in each object file (One Definition Rule violation).
You can create "header-only" C libraries if all your functions are marked as static, that is, not visible outside the translation unit. But it also means you will get a copy of all the static functions in each translation unit that includes the header file.
It is a bit different in C++: inline functions are not static, symbols emitted by the compiler are still visible by the linker, but the linker can discard duplicates, rather than giving up ("weak" symbols).
It's not idiomatic to write C code in the headers, unless it's based on macros (e.g. queue(3)). In C++, the main reason to keep code in the headers are templates, which may result in code instantiation for different template parameters, which is not applicable to C.
You do not link headers.
In C++ it's slightly easier to write code that's already better-off in headers than in separately-compiled modules because templates require it. 1
But you can also use the inline keyword for functions, which exists in C as well as C++. 2
// Won't cause redefinition link errors, because of 6.7.4/5
inline void foo(void) {
// ...
}
[c99: 6.7.4/5:] A function declared with an inline function
specifier is an inline function. The function specifier may appear
more than once; the behavior is the same as if it appeared only once.
Making a function an inline function suggests that calls to the
function be as fast as possible. The extent to which such
suggestions are effective is implementation-defined.
You're a bit stuck when it comes to data objects, though.
1 - Sort of.
2 - C99 for sure. C89/C90 I'd have to check.
Boost makes heavy use templates and template meta-programming which you cannot emulate (all that easily) in C.
But you can of course cheat by having declarations and code in C headers which you #include but that is not the same thing. I'd say "When in Rome..." and program C as per C conventions with libraries.
Yes, it is quite possible. Declare all functions in headers and either all as static or just use a single compilation unit (i.e. only a single c file) in your projects.
As a personal anecdote, I know quite a number of physicists who insist that this technique is the only true way to program C. It is beneficial because it's the poor man's version of -fwhole-program, i.e. makes optimizations based on the knowledge of function behaviour possible. It is practical because you don't need to learn about using the linker flags. It is a bad idea because your whole program must be compiled as a whole and recompiled with each minor change.
Personally, I'd recommend to let it be or at least go with static for only a few functions.