Locally included header files

May 22, 2010 at 9:23pm
I know its possible to #include header files locally in functions, and this will compile, but what is the rationale behind it?

Does it have to do with global variables defined in the header file?

If for instance you wanted to use two functions, both reliant on some header which uses global variables, but wanted to keep the variables independent from each other, by #including the headers locally, would that be the same as having a second "instance" of the class or header? (By instance I mean, if you were to call main() recursively, and if your compiler would allow you to get away with it, you would have a second "instance" of your program.... )

For example, the rand() function defined in <stdlib.h> utilizes a public global variable for the seed, and (I presume) a private global variable to keep track of the iteration. This implementation however, does not allow the user to use 2 separate random functions (hereafter: rand1(), rand2()) with different seeds, without having to pseudorecursively reiterate to the last point where rand1() left off before switching to rand2().
For instance you would have to do something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdlib.h>
#inlude <time.h>
#include <iostream>

using namespace std;

int getseed();
int it1 = 0, it2 = 0;
const int seed1 = time(NULL), seed2 = getseed();

int rand1(), rand2();

int main()
{
}

int rand1()
{
    srand(seed1);
    int x;
    for (int i = 0; i < it1; ++i)
        {
            x = rand();
        }
    ++it1;
    return x;
}

int rand2()
{
    srand(seed2);
    int x; 
    for (int i = 0; i < it2; ++i)
        {
            x = rand();
        }
    ++it2;
    return x;    
}

int getseed()
{
    int s; cout << "Enter the seed value. /n" << endl; cin >> s;
    return s;
}


I say rand1() & rand2() are pseudo-recursive, not because they call on themselves, but because they requre as much (or almost as much) overhead as if they did, and it is obvious that this is a very inefficient approach. Of course it would be most effective to write your own rand class, that way you would be able to skip to the iteration, just as I presume rand() does, without having to calculate the values of every iteration up to the iteration you want. But lets just say I want a temporary fix for this, would the following code work, compile, be effective & efficient?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <time.h>
#include <iostream>

int getseed(){int s; cout << "Enter the seed. " << endl; cin >> s; return s;}

const int seed1 = time(NULL); const int seed2 = getseed();

int main()
{}

int rand1()
{
   #include <stdlib.h>
   #ifndef A
   #define A
   srand(seed1);
   #endif
   int x = rand();
   return x;
}

int rand2()
{   
   #include <stdlib.h>
   #ifndef B
   #define B
   srand(seed2);
   #endif
   int x = rand();
   return x;
   #endif
}


or would rand1 & rand2 return the same value's every time they are called? If so how to go about accomplishing this? and why is it possible to include header files locally?




May 22, 2010 at 9:39pm
You never want to include header files locally in functions. You can do it because the preprocessor will let you. But you should not do it because it abuses the concept of include files, is unmaintainable, and will confuse the hell out of anyone that looks at your code.
May 22, 2010 at 9:45pm
well would the above code work?
May 22, 2010 at 9:51pm
Compile it and find out; it will be better to see for yourself.
May 22, 2010 at 9:51pm

You never want to include header files locally in functions.

Why?
Last edited on May 22, 2010 at 9:52pm
May 22, 2010 at 10:03pm
Because it abuses the concept of include files, is unmaintainable, and will confuse the hell out of anyone that looks at your code.
May 22, 2010 at 10:24pm
I would be surprised if that could even compile.
May 22, 2010 at 10:28pm
That would compile in theory, however chrisname is right: it will just confuse people. That said, if you want to create unmaintainable code, go right ahead.

-Albatross
May 22, 2010 at 10:28pm
Well it doesn't confuse me. I was hoping for a little more insight, i.e. what is the central concept of include files to which you refer that it abuses? How is it unmaintainable? I'm not arguing per se, just curious. Also is my compiler, Codeblocks, standard-compliant if it allows me to include header files locally?
May 22, 2010 at 10:30pm
No. If it allows inclusion of header files locally, then it may or may not be standard. If it is standard, I think it must.

The concept of include files is to create an "interface" between C++ files, per-se. You can include C++ files, however that's another bad idea (EDIT: ask the other members why, I don't answer questions about "evil" functions without tripping over my 'e' key). The header files provide a layer, and are much safer in that aspect.

-Albatross
Last edited on May 22, 2010 at 10:31pm
May 22, 2010 at 11:25pm
Whether or not the above will work depends entirely on how the header is structured.

Remember that #include is basically like a copy/paste operation. Something like this is totally legal:

1
2
// five.h
5

1
2
// plus.h
+

1
2
// semi.h
;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// main.cpp
#include <iostream>

int main()
{
  int foo = 
#include "five.h"
#include "plus.h"
#include "five.h"
#include "semi.h"

  std::cout << foo; // prints "10"

  return 0;
}


Of course such code is fugly and horrendous.
May 22, 2010 at 11:31pm
wow. you just gave me an idea of how to parse.
May 22, 2010 at 11:53pm
My post was technically correct, but now I fear I've turned you down a terrible path.

Listen to what everyone else is saying. Locally including headers is a bad idea because it's unintuitive, and it has other ill sideeffects you might not realize.

let's take your example in your first post:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int rand1()
{
   #include <stdlib.h>
   #ifndef A
   #define A
   srand(seed1);
   #endif
   int x = rand();
   return x;
}

int rand2()
{   
   #include <stdlib.h>
   #ifndef B
   #define B
   srand(seed2);
   #endif
   int x = rand();
   return x;
}


what if stdlib.h looks like this:

1
2
3
4
5
#ifndef STDLIB_H_INCLUDED
#define STDLIB_H_INCLUDED
void srand(unsigned);
int rand();
#endif 


Remember that the preprocessor and #defines ignore C++ scope rules. So if you #define something locally in a function, it does not get undef'd at the following }.

So the above would work for rand1() because srand and rand would be prototyped locally inside the rand1 function

However you'd be screwed for rand2 because the include guard would prevent it from being included a second time, which means rand,srand would not be visible from rand2.


What's worse, you have no way to know what stdlib.h will look like. Even if it's a certain way on YOUR computer, it might be totally different on someone else's computer (different compilers may have different implementations, etc).


Plus this is one of those unorthodoxed things where people can probably figure out what you're doing, but it's more confusing than useful.


So anyway....

possible? yes
a good idea? hell no
Last edited on May 22, 2010 at 11:53pm
May 23, 2010 at 12:09am
I fear I've turned you down a terrible path.

Relax, I was only joking. But it did in fact give me an idea of how to implement a solution for a problem that I had thought about before. (But I will probably not be attempting it, at least not unless I get really really bored and end up having a lot of time on me hands. )

About this I'm serious though:

However you'd be screwed for rand2 because the include guard would prevent it from being included a second time, which means rand,srand would not be visible from rand2.


Could I edit out the include guard from stdlib.h, as long as I only use it for this one project, and only have the 2 includes in my 2 functions and no more. Would stdlib.h include any headers that would include <stdlib.h> that I would need to be aware of?

edit: I could even copy and rename the file stdlib2.h to be sure no one else uses my version by mistake.
Last edited on May 23, 2010 at 12:12am
May 23, 2010 at 12:16am
Could I edit out the include guard from stdlib.h, as long as I only use it for this one project,


editing common lib header files is a bad idea because there's no way to guarantee that it's only used for this one project. The only way to make absolutely sure would be to copy/paste it to another location and possibly rename it to avoid confusion... in which case yeah that would work.

But of course removing the include guard might cause other troubles. Include guards are there for a reason, after all. Removing them opens up the possibility of circular inclusion problems, or multiply defined symbols.

And again... this is all more confusing than useful. Why is is so bad to have it #included globally like normal?

Would stdlib.h include any headers that would include <stdlib.h> that I would need to be aware of?


Possibly, yeah. There's no way to know what it does.

And just because it does something for you, doesn't mean it does that for someone else. Remember that these headers may look totally different from compiler to compiler. Manipulating this like this will make it difficult for other people to compiler your code.
Last edited on May 23, 2010 at 12:17am
May 23, 2010 at 2:55am
It is entirely possible (and sometimes useful) to #include headers in a local context.
The problems are not only understanding them, but that a header really only works well in a global context.

Consider the following header:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#pragma once
#ifndef FOOEY_HPP
#define FOOEY_HPP

#define QUUX 42

namespace barf
  {
  int eat( int );
  };

extern int zog;

#endif 

If you include it in the global context (as you should), then you can use its contents anywhere within your source file. If you include it in a local context, you are spilling macro definitions into the global context, and making it so that you cannot include the file again in any other context in the same source file.

More advanced header files may actually fail when inserted in a local context. (Just about anything from Boost comes to mind.)

Moreover, you could easily create linkage problems with local #includes.


So when is a local include useful? I would say "never", but it is possible that you may wish to adjust some local piece of information through external resources. For example, a local table generated by another program would be ideal to locally #include. We remember, of course, that said header was specially designed to be locally #included in one spot.

Even in that case, though, C++ gives you many ways to avoid such a construct. (Depending on what you are doing in C, you may or may not want to do it.)


Finally, the problem with such things is that your files know too much about each other -- source encapsulation spills out to the preprocessor and linker, instead of staying within the compiler proper. This becomes a significant problem when porting code to other platforms.

Hope this helps.
May 23, 2010 at 4:45am
If what you are after are multiple random number generators, each with distinct state, then you should look at the Boost Random library. It solves that problem.

To answer the questions "will it work?", the answer is "no" because of the header guards in stdlib.h and because rand() still refers to the same single instance in the C library. And the variables that store its state are not defined in headers. They are declared in headers and defined in source files that are used to build the C standard library.

It is best to avoid abusing the compiler and preprocessor when one cannot figure out the right way to solve a problem.
Topic archived. No new replies allowed.