[GiNaC-list] Include Guards

Sheplyakov Alexei varg at theor.jinr.ru
Thu Jan 20 10:10:30 CET 2005


On Wed, Jan 19, 2005 at 03:55:19PM -0600, Jason Dusek wrote:
> In the FAQ, they discuss a problem with multiple inclusions of a
> header where global symbols are defined:

The problem has NOTHING to do with multiple inclusions of a
header. The actual problem is declaration of global variables
in different compilation units by inclusion a _single_ header
file, like this:

// file bogus.h
#ifndef VARGS_BOGUS_H
#define VARGS_BOGUS_H
#include <ginac/ginac.h>
const GiNaC::symbol x("x");
#endif

// file fun1.cpp
#include <ginac/ginac.h>
#include "bogus.h"
const GiNaC::ex fun1() { return x; }

// file fun2.cpp
#include <ginac/ginac.h>
#include "bogus.h"
const GiNaC::ex fun2() { return x; }

// file main.cpp
#include <iostream>
#include <ginac/ginac.h>
using namespace std;
using namespace GiNaC;
extern const ex fun1();
extern const ex fun2();

int main(int argc, char* argv)
{
	ex bogus = fun1() - fun2();
	// print expression as a tree
	cout << tree << bogus << endl;
	return 0;
}


On my system, this program will print

add @0x805ef88, hash=0xb7e7ae1a, flags=0x3, nops=2
    x (symbol) @0x805eda8, serial=2, hash=0x670d3697, flags=0xf, domain=0
    1 (numeric) @0x804fde8, hash=0x160af41d, flags=0xf
    -----
    x (symbol) @0x805ed70, serial=1, hash=0x79ba0000, flags=0xf, domain=0
    -1 (numeric) @0x804fc58, hash=0xd60af41d, flags=0xf
    =====

So, `bogus' is _not_ zero, because there are two _different_ symbols
(with the same print-name x): one of them was defined in the file
fun1.cpp, another -- in fun2.cpp. Note, that in this example header
file "bogus.h" gets included only once. 

> ================================================
> Q: I have various modules, some global variables and...
> 
> A: ...and you are getting weird results with symbols not being
> identical? Imagine this situation: A file globals.h declares symbol
> x("x"). Two other modules #include "globals.h", do something with
> symbol x and return an expression ex containing the symbol to the
> caller (e.g. to main()). When the caller combines the two expressions
> there are really two different symbols both with the same print-name
> x. This may cause terms like x-x to stay around which will never be
> simplified to 0 because the system has no knowledge that the two
> symbols are supposed to be the same. How should it? After all the
> declarations really happend in different compilation units!
> ================================================
> Can include guards solve this problem?

No, they can't.

> Do I *have* to make that evil factory initializer thingy?

You might use something like

// file bogus.h
#ifndef VARGS_GLOBAL_X_H
#define VARGS_GLOBAL_X_H
#include <ginac/ginac.h>
extern GiNaC::symbol x;
#endif

// file bogus.cpp
#include <ginac/ginac.h>
#include "bogus.h"
using namespace GiNaC;
symbol x("x");

// file fun1.cpp
#include <ginac/ginac.h>
#include "bogus.h"

const GiNaC::ex fun1() { return x; }

// file fun2.cpp
#include <ginac/ginac.h>
#include "bogus.h"

const GiNaC::ex fun2() { return x; }

// file main.cpp
#include <iostream>
#include <ginac/ginac.h>
using namespace std;
using namespace GiNaC;
extern const ex fun1();
extern const ex fun2();

int main(int argc, char* argv)
{
	ex bogus = fun1() - fun2();
	// print expression as a tree
	cout << tree << bogus << endl;
	// will print zero
	return 0;
}

But (IMHO) such a code is even more evil :)


Best regards,
	Alexei.




More information about the GiNaC-list mailing list