Locally included header files

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?




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.
well would the above code work?
Compile it and find out; it will be better to see for yourself.

You never want to include header files locally in functions.

Why?
Last edited on
Because it abuses the concept of include files, is unmaintainable, and will confuse the hell out of anyone that looks at your code.
I would be surprised if that could even compile.
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
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?
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
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.
wow. you just gave me an idea of how to parse.
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
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
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
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.
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.