Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

avoiding redefinition of variables for single header

I've a single header requirement on a code, which means there should be no splitting of declarations and definitions into separate header and source files. I've implemented it properly and it works as intended for my use case, where this header file was meant to be included in only single source file.

Now when it comes to it's use in multiple source files(where more than one .cpp includes it), it will fail with linker error along the lines that some variables are being redeclared. That is because I've the code like -

#ifndef HEADER_HPP
#define HEADER_HPP

....

std::streambuf const *R_coutbuf = std::cout.rdbuf();
std::streambuf const *R_cerrbuf = std::cerr.rdbuf();
std::streambuf const *R_clogbuf = std::clog.rdbuf();

void doSomething(){
    [uses if(R_coutbuf) and others]
}

....

#endif HEADER_HPP

Now the best solution would be to declare those vars in header file and define/assign them in single cpp file, but as I said I want to be able to do this with a single header file. Which brings to the problem that if multiple source files will include it, there will be redeclarations.

So far I'm not sure how should I be able to do this but I've two ideas -

#ifdef DEFINE_VARIABLES
#define EXTERN /* nothing */
#else
#define EXTERN extern int
#endif /* DEFINE_VARIABLES */

EXTERN global_variable = something;

I'm not so sure about it, would this even work?

And the second way I thought about is to put it in an anonymous namespace, am trying this one and so far its building successfully -

#ifndef HEADER_HPP
#define HEADER_HPP

....

namespace R {

    namespace {
        std::streambuf const *R_coutbuf = std::cout.rdbuf();
        std::streambuf const *R_cerrbuf = std::cerr.rdbuf();
        std::streambuf const *R_clogbuf = std::clog.rdbuf();
    }
    void doSomething(){
        [uses if(R_coutbuf) and others]
    }
}

....

#endif HEADER_HPP

Is there any other way I could achieve this? Are there any problems with either of the ways I described above.

like image 891
Abhinav Gauniyal Avatar asked Sep 12 '16 12:09

Abhinav Gauniyal


People also ask

How can we avoid redefinition?

Answer: The include guards in header file in C, C++ is used to avoid compiler error i.e. redefinition of function, variable or class.

How do you fix a redefinition error in C programming?

Re “How do you fix a redefinition error in C programming?”, you do that by removing the redefinition. Compilers can get confused when subjected to unexpected repetition in source code. So when they complain about it, the fix is to find and remove the repetition.

What does redefinition mean in C++?

A redefinition is an attempt to redefine the same variable, e.g.: int a = 5; int a = 6; Also. int foo(); is not a definition. It's a declaration.

How to redefine variable in C?

In C, you cannot redefine an existing variable.


2 Answers

You could make your variable a local static variable in a function:

inline std::streambuf const*& R_coutbuf() {
    static std::streambuf const* b = std::cout.rdbuf();
    return b;
}
like image 79
Chris Drew Avatar answered Sep 21 '22 23:09

Chris Drew


Are there any problems with either of the ways I described above.

Macro trick

  • pros
    • Produces minimal number of variables in object files. See the con of anonymous namespace.
  • cons
    • Very fragile. When including the header, a programmer must know whether any of other existing sources include the variable definitions. This does not scale well when the number of source files increases

Internal linkage (anonymous namespace)

  • pros
    • Doesn't have the disadvantage of the macro trick.
  • cons
    • Each object file that includes the header will have their own copy of the variables. I'm not certain, but the variables are const and all will have the same value at run time, the linker may be able to throw away the duplicates. In any case, the difference is only a few bytes worth for your program. Modifying individual variables as opposed to modifying a shared variable would change the meaning of the program.

For comparison, let us consider separate source file option, which you have ruled out.

  • pros
    • Produces minimal number of variables in object files, like the macro trick.
    • Doesn't have the disadvantage of the macro trick.
  • cons
    • None (unless you consider having a separate source file a con by itself).

Is there any other way I could achieve this?

Not really. You can use static keyword instead of anonymous namespace to declare internal linkage.


PS. If you define any non-template functions in the header, they must be declared inline. Your anonymous namespace example fails to do this.

like image 38
eerorika Avatar answered Sep 18 '22 23:09

eerorika