Why isn't #pragma once automatically assumed?
up vote
48
down vote
favorite
What's the point of telling the compiler specifically to include the file only once? Wouldn't it make sense by default? Is there even any reason to include a single file multiple times? Why not just assume it? Is it to do with specific hardware?
c++ c pragma
|
show 18 more comments
up vote
48
down vote
favorite
What's the point of telling the compiler specifically to include the file only once? Wouldn't it make sense by default? Is there even any reason to include a single file multiple times? Why not just assume it? Is it to do with specific hardware?
c++ c pragma
23
Is there even any reason to include a single file multiple times? => Could be. A file might have conditional compilation#ifdefs
in it. So you might say#define MODE_ONE 1
and then#include "has-modes.h"
, and then#undef MODE_ONE
with#define MODE_TWO 1
and#include "has-modes.h"
again. The preprocessor is agnostic about these kinds of things, and maybe sometimes they can make sense.
– HostileFork
Nov 21 at 16:40
62
It would make sense as the default. Just not the one they picked when C programmers still rode horses, carried guns and had 16KB of memory
– Hans Passant
Nov 21 at 16:41
11
You can include<assert.h>
multiple times, with different definitions ofNDEBUG
, in the same source file.
– Pete Becker
Nov 21 at 16:45
3
As for#pragma once
itself, there are hardware environments (typically with networked drives and possible multiple paths to the same header) where it won't work right.
– Pete Becker
Nov 21 at 16:48
11
If you have#pragma once
assumed, what is the way of countermanding that default?#pragma many
? How many compilers have implemented anything like that?
– Jonathan Leffler
Nov 21 at 17:20
|
show 18 more comments
up vote
48
down vote
favorite
up vote
48
down vote
favorite
What's the point of telling the compiler specifically to include the file only once? Wouldn't it make sense by default? Is there even any reason to include a single file multiple times? Why not just assume it? Is it to do with specific hardware?
c++ c pragma
What's the point of telling the compiler specifically to include the file only once? Wouldn't it make sense by default? Is there even any reason to include a single file multiple times? Why not just assume it? Is it to do with specific hardware?
c++ c pragma
c++ c pragma
edited Nov 21 at 16:48
PSkocik
31.5k54569
31.5k54569
asked Nov 21 at 16:35
Johnny Cache
27827
27827
23
Is there even any reason to include a single file multiple times? => Could be. A file might have conditional compilation#ifdefs
in it. So you might say#define MODE_ONE 1
and then#include "has-modes.h"
, and then#undef MODE_ONE
with#define MODE_TWO 1
and#include "has-modes.h"
again. The preprocessor is agnostic about these kinds of things, and maybe sometimes they can make sense.
– HostileFork
Nov 21 at 16:40
62
It would make sense as the default. Just not the one they picked when C programmers still rode horses, carried guns and had 16KB of memory
– Hans Passant
Nov 21 at 16:41
11
You can include<assert.h>
multiple times, with different definitions ofNDEBUG
, in the same source file.
– Pete Becker
Nov 21 at 16:45
3
As for#pragma once
itself, there are hardware environments (typically with networked drives and possible multiple paths to the same header) where it won't work right.
– Pete Becker
Nov 21 at 16:48
11
If you have#pragma once
assumed, what is the way of countermanding that default?#pragma many
? How many compilers have implemented anything like that?
– Jonathan Leffler
Nov 21 at 17:20
|
show 18 more comments
23
Is there even any reason to include a single file multiple times? => Could be. A file might have conditional compilation#ifdefs
in it. So you might say#define MODE_ONE 1
and then#include "has-modes.h"
, and then#undef MODE_ONE
with#define MODE_TWO 1
and#include "has-modes.h"
again. The preprocessor is agnostic about these kinds of things, and maybe sometimes they can make sense.
– HostileFork
Nov 21 at 16:40
62
It would make sense as the default. Just not the one they picked when C programmers still rode horses, carried guns and had 16KB of memory
– Hans Passant
Nov 21 at 16:41
11
You can include<assert.h>
multiple times, with different definitions ofNDEBUG
, in the same source file.
– Pete Becker
Nov 21 at 16:45
3
As for#pragma once
itself, there are hardware environments (typically with networked drives and possible multiple paths to the same header) where it won't work right.
– Pete Becker
Nov 21 at 16:48
11
If you have#pragma once
assumed, what is the way of countermanding that default?#pragma many
? How many compilers have implemented anything like that?
– Jonathan Leffler
Nov 21 at 17:20
23
23
Is there even any reason to include a single file multiple times? => Could be. A file might have conditional compilation
#ifdefs
in it. So you might say #define MODE_ONE 1
and then #include "has-modes.h"
, and then #undef MODE_ONE
with #define MODE_TWO 1
and #include "has-modes.h"
again. The preprocessor is agnostic about these kinds of things, and maybe sometimes they can make sense.– HostileFork
Nov 21 at 16:40
Is there even any reason to include a single file multiple times? => Could be. A file might have conditional compilation
#ifdefs
in it. So you might say #define MODE_ONE 1
and then #include "has-modes.h"
, and then #undef MODE_ONE
with #define MODE_TWO 1
and #include "has-modes.h"
again. The preprocessor is agnostic about these kinds of things, and maybe sometimes they can make sense.– HostileFork
Nov 21 at 16:40
62
62
It would make sense as the default. Just not the one they picked when C programmers still rode horses, carried guns and had 16KB of memory
– Hans Passant
Nov 21 at 16:41
It would make sense as the default. Just not the one they picked when C programmers still rode horses, carried guns and had 16KB of memory
– Hans Passant
Nov 21 at 16:41
11
11
You can include
<assert.h>
multiple times, with different definitions of NDEBUG
, in the same source file.– Pete Becker
Nov 21 at 16:45
You can include
<assert.h>
multiple times, with different definitions of NDEBUG
, in the same source file.– Pete Becker
Nov 21 at 16:45
3
3
As for
#pragma once
itself, there are hardware environments (typically with networked drives and possible multiple paths to the same header) where it won't work right.– Pete Becker
Nov 21 at 16:48
As for
#pragma once
itself, there are hardware environments (typically with networked drives and possible multiple paths to the same header) where it won't work right.– Pete Becker
Nov 21 at 16:48
11
11
If you have
#pragma once
assumed, what is the way of countermanding that default? #pragma many
? How many compilers have implemented anything like that?– Jonathan Leffler
Nov 21 at 17:20
If you have
#pragma once
assumed, what is the way of countermanding that default? #pragma many
? How many compilers have implemented anything like that?– Jonathan Leffler
Nov 21 at 17:20
|
show 18 more comments
6 Answers
6
active
oldest
votes
up vote
61
down vote
accepted
There are multiple related questions here:
Why is
#pragma once
not automatically enforced?
Because there are situations in which you want to include files more than once.Why would you want to include a file multiple times?
Several reasons have been given in other answers (Boost.Preprocessor, X-Macros, including data files). I would like to add a particular example of "avoid code duplication": OpenFOAM encourages a style where#include
ing bits and pieces within functions is a common concept. See for example this discussion.Ok, but why is it not the default with an opt-out?
Because it is not actually specified by the standard.#pragma
s are by definition implementation-specific extensions.Why has
#pragma once
not become a standardized feature yet (as it is widely supported)?
Because pinning down what is "the same file" in a platform-agnostic way is actually surprisingly hard. See this answer for more information.
And another take on why not standardizeonce
– user4581301
Nov 21 at 19:05
4
In particular, see this example for a case of wherepragma once
fails but include guards would have worked. Identifying files by location doesn't work either because sometimes the same file occurs multiple times in a project (e.g. you have 2 submodules that both include a header-only library in their headers and check out their own copy of it)
– M.M
Nov 21 at 19:46
4
Not all pragmas are implementation-specific extensions. E.g.#pragma STDC
family. But they all do control implementation-defined behavior.
– Ruslan
Nov 21 at 20:58
2
@user4581301 This answer over exaggerates the problem with pragma once and does not consider troubles due to include guards. In both case some discipline is needed. With include guards one must make sure to use a name that will not be used in an other file (which will happen after a file copy modify). With pragma once, one has to decide what is the unique right place for its file, which is a good thing after all.
– Oliv
Nov 21 at 22:42
3
@Mehrdad: Are you seriously suggesting that compilers write to source files!? If a compiler sees#ifndef XX
, it must can't know whether there's anything following the corresponding#endif
until it's read the entire file. A compiler that keeps track of whether the outermost#ifndef
encloses the entire file and notes what macro it checks may be able to avoid rescanning the file, but a directive to say there's nothing of importance following the current point would seem seem nicer than relying upon compilers to remember such things.
– supercat
Nov 22 at 6:47
|
show 8 more comments
up vote
31
down vote
You can use #include
anywhere in a file, not just at global scope - like, inside a function (and multiple times if needed). Sure, ugly and not good style, but possible and occasionally sensible (depending on the file you include). If #include
was only ever a one time thing then that wouldn't work. #include
just does dumb text substitution (cut'n'paste) after all, and not everything you include has to be a header file. You might - for example - #include
a file containing auto generated data containing the raw data to initialize a std::vector
. Like
std::vector<int> data = {
#include "my_generated_data.txt"
}
And have "my_generated_data.txt" be something generated by the build system during compilation.
Or maybe I'm lazy/silly/stupid and put this in a file (very contrived example):
const noexcept;
and then I do
class foo {
void f1()
#include "stupid.file"
int f2(int)
#include "stupid.file"
};
Another, slightly less contrived, example would be a source file where many functions need to use a large amount of types in a namespace, but you don't want to just say using namespace foo;
globally since that would polute the global namespace with a lot of other stuff you don't want. So you create a file "foo" containing
using std::vector;
using std::array;
using std::rotate;
... You get the idea ...
And then you do this in your source file
void f1() {
#include "foo" // needs "stuff"
}
void f2() {
// Doesn't need "stuff"
}
void f3() {
#include "foo" // also needs "stuff"
}
Note: I'm not advocating doing things like this. But it is possible and done in some codebases and I don't see why it should not be allowed. It does have its uses.
It could also be that the file you include behaves differently depending on the value of certain macros (#define
s). So you may want to include the file in multiple locations, after first having changed some value, so you get different behaviour in different parts of your source file.
This would still work if all headers were pragma once. As long as you didn't include the generated data more than once.
– PSkocik
Nov 21 at 16:57
1
@PSkocik But maybe I need to include it more than once. Why shouldn't I be able to?
– Jesper Juhl
Nov 21 at 16:59
1
@JesperJuhl That's the point. You won't need to include it more than once ever. You currently have the option, but the alternative isn't much worse, if at all.
– Johnny Cache
Nov 21 at 17:08
8
@PSkocik If I change the value of#define
s before each include that changes the behaviour of the included file then I may very well need to include it multiple times to get those different behaviours in different parts of my source file.
– Jesper Juhl
Nov 21 at 17:28
add a comment |
up vote
21
down vote
Including multiple times is usable e.g., with the X-macro technique:
data.inc:
X(ONE)
X(TWO)
X(THREE)
use_data_inc_twice.c
enum data_e {
#define X(V) V,
#include "data.inc"
#undef X
};
char const* data_e__strings={
#define X(V) [V]=#V,
#include "data.inc"
#undef X
};
I don't know about any other use.
That sounds overly complex. Any reason not to just include those definitions in the file in the first place?
– Johnny Cache
Nov 21 at 16:50
2
@JohnnyCache: The example is a simplified version of how X-macros work. Please read the link; they're extremely useful in some cases for doing complex manipulations of tabular data. In any significant usage of X-macros, there would be no way you could just "include those definitions in the file".
– Nicol Bolas
Nov 21 at 16:51
2
@Johnny - yes - one good reason is to ensure consistency (hard to do by hand when you have just a few dozen elements, never mind hundreds).
– Toby Speight
Nov 21 at 16:51
@TobySpeight Heh, I suppose I could spare a single line of code to avoid writing thousands somewhere else. Makes sense.
– Johnny Cache
Nov 21 at 16:52
1
To avoid duplication. Especially if the file is large. Admittedly, you could just use a big macro containing the X macro list but since projects could be using this, mandating#pragma once
behavior would be a breaking change.
– PSkocik
Nov 21 at 16:52
|
show 2 more comments
up vote
15
down vote
You seem to be operating under the assumption that the purpose of the "#include" feature even existing in the language is to provide support for decomposition of programs into multiple compilation units. That is incorrect.
It can perform that role, but that was not its intended purpose. C was originally developed as slightly higher-level language than PDP-11 Macro-11 Assembly for reimplementing Unix. It had a macro preprocessor because that was a feature of Macro-11. It had the ability to textually include macros from another file because that was a feature of Macro-11 that the existing Unix they were porting to their new C compiler had made use of.
Now it turns out that "#include" is useful for separating code into compilation units, as (arguably) a bit of a hack. However, the fact that this hack existed meant that it became The Way that is done in C. The fact that a way existed meant no new method ever needed to be created to provide this functionality, so nothing safer (eg: not vulnerable to multiple-inclusion) was ever created. Since it was already in C, it got copied into C++ along with most of the rest of C's syntax and idioms.
There is a proposal for giving C++ a proper module system so this 45 year old preprocessor hack can finally be dispensed with. I don't know how imminent this is though. I've been hearing about it being in the works for more than a decade.
2
As usual, to understand C and C++, you need to understand their history.
– Jack Aidley
Nov 22 at 12:27
It is reasonable to expect that modules will land in February.
– Davis Herring
Nov 22 at 20:31
3
@DavisHerring - Yes, but which February?
– T.E.D.
Nov 23 at 0:02
add a comment |
up vote
9
down vote
No, this would significantly hinder the options available to, for example, library writers. For example, Boost.Preprocessor allows one to use pre-processor loops, and the only way to achieve those is by multiple inclusions of the same file.
And Boost.Preprocessor is a building block for many very useful libraries.
1
It would not hinder any of that. OP asked about a default behaviour, not an unchangeable behaviour. It would be entirely sensible to change the default and instead provide a preprocessor flag#pragma reentrant
or something along these lines. Hindsight is 20/20.
– Konrad Rudolph
Nov 23 at 11:12
It would hinder it in the sense of forcing people to update their libraries and dependencies, @KonradRudolph. Not always a problem, but it could cause issues with some legacy programs. Ideally, there would also be a command-line switch to specify whether the default isonce
orreentrant
, to mitigate this or other potential issues.
– Justin Time
yesterday
@JustinTime Well as my comment says it’s clearly not a backwards compatible (and therefore feasible) change. The question, however, was why it was initially designed that way, not why it’s not being changed. And the answer to that is, unambiguously, that the original design was a huge mistake with far-reaching consequences.
– Konrad Rudolph
21 hours ago
add a comment |
up vote
7
down vote
In the firmware for the product I mainly work on, we need to be able to specify where functions and global/static variables should be allocated in memory. Real-time processing needs to live in L1 memory on chip so the processor can access it directly, fast. Less important processing can go in L2 memory on chip. And anything that doesn't need to be handled particularly promptly can live in the external DDR and go through caching, because it doesn't matter if it's a little slower.
The #pragma to allocate where things go is a long, non-trivial line. It'd be easy to get it wrong. The effect of getting it wrong would be that the code/data would be silently put into default (DDR) memory, and the effect of that might be closed-loop control stopping working for no reason that's easy to see.
So I use include files, which contain just that pragma. My code now looks like this.
Header file...
#ifndef HEADERFILE_H
#define HEADERFILE_H
#include "set_fast_storage.h"
/* Declare variables */
#include "set_slow_storage.h"
/* Declare functions for initialisation on startup */
#include "set_fast_storage.h"
/* Declare functions for real-time processing */
#include "set_storage_default.h"
#endif
And source...
#include "headerfile.h"
#include "set_fast_storage.h"
/* Define variables */
#include "set_slow_storage.h"
/* Define functions for initialisation on startup */
#include "set_fast_storage.h"
/* Define functions for real-time processing */
You'll notice multiple inclusions of the same file there, even just in the header. If I mistype something now, the compiler will tell me it can't find the include file "set_fat_storage.h" and I can easily fix it.
So in answer to your question, this is a real, practical example of where multiple inclusion is required.
3
I would say your use case is a motivating example for the_Pragma
directive. The same pragmas can now be expanded from regular macros. So no need to include more than once.
– StoryTeller
Nov 22 at 4:13
@StoryTeller Good point, I could do.
– Graham
Nov 22 at 15:35
add a comment |
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
61
down vote
accepted
There are multiple related questions here:
Why is
#pragma once
not automatically enforced?
Because there are situations in which you want to include files more than once.Why would you want to include a file multiple times?
Several reasons have been given in other answers (Boost.Preprocessor, X-Macros, including data files). I would like to add a particular example of "avoid code duplication": OpenFOAM encourages a style where#include
ing bits and pieces within functions is a common concept. See for example this discussion.Ok, but why is it not the default with an opt-out?
Because it is not actually specified by the standard.#pragma
s are by definition implementation-specific extensions.Why has
#pragma once
not become a standardized feature yet (as it is widely supported)?
Because pinning down what is "the same file" in a platform-agnostic way is actually surprisingly hard. See this answer for more information.
And another take on why not standardizeonce
– user4581301
Nov 21 at 19:05
4
In particular, see this example for a case of wherepragma once
fails but include guards would have worked. Identifying files by location doesn't work either because sometimes the same file occurs multiple times in a project (e.g. you have 2 submodules that both include a header-only library in their headers and check out their own copy of it)
– M.M
Nov 21 at 19:46
4
Not all pragmas are implementation-specific extensions. E.g.#pragma STDC
family. But they all do control implementation-defined behavior.
– Ruslan
Nov 21 at 20:58
2
@user4581301 This answer over exaggerates the problem with pragma once and does not consider troubles due to include guards. In both case some discipline is needed. With include guards one must make sure to use a name that will not be used in an other file (which will happen after a file copy modify). With pragma once, one has to decide what is the unique right place for its file, which is a good thing after all.
– Oliv
Nov 21 at 22:42
3
@Mehrdad: Are you seriously suggesting that compilers write to source files!? If a compiler sees#ifndef XX
, it must can't know whether there's anything following the corresponding#endif
until it's read the entire file. A compiler that keeps track of whether the outermost#ifndef
encloses the entire file and notes what macro it checks may be able to avoid rescanning the file, but a directive to say there's nothing of importance following the current point would seem seem nicer than relying upon compilers to remember such things.
– supercat
Nov 22 at 6:47
|
show 8 more comments
up vote
61
down vote
accepted
There are multiple related questions here:
Why is
#pragma once
not automatically enforced?
Because there are situations in which you want to include files more than once.Why would you want to include a file multiple times?
Several reasons have been given in other answers (Boost.Preprocessor, X-Macros, including data files). I would like to add a particular example of "avoid code duplication": OpenFOAM encourages a style where#include
ing bits and pieces within functions is a common concept. See for example this discussion.Ok, but why is it not the default with an opt-out?
Because it is not actually specified by the standard.#pragma
s are by definition implementation-specific extensions.Why has
#pragma once
not become a standardized feature yet (as it is widely supported)?
Because pinning down what is "the same file" in a platform-agnostic way is actually surprisingly hard. See this answer for more information.
And another take on why not standardizeonce
– user4581301
Nov 21 at 19:05
4
In particular, see this example for a case of wherepragma once
fails but include guards would have worked. Identifying files by location doesn't work either because sometimes the same file occurs multiple times in a project (e.g. you have 2 submodules that both include a header-only library in their headers and check out their own copy of it)
– M.M
Nov 21 at 19:46
4
Not all pragmas are implementation-specific extensions. E.g.#pragma STDC
family. But they all do control implementation-defined behavior.
– Ruslan
Nov 21 at 20:58
2
@user4581301 This answer over exaggerates the problem with pragma once and does not consider troubles due to include guards. In both case some discipline is needed. With include guards one must make sure to use a name that will not be used in an other file (which will happen after a file copy modify). With pragma once, one has to decide what is the unique right place for its file, which is a good thing after all.
– Oliv
Nov 21 at 22:42
3
@Mehrdad: Are you seriously suggesting that compilers write to source files!? If a compiler sees#ifndef XX
, it must can't know whether there's anything following the corresponding#endif
until it's read the entire file. A compiler that keeps track of whether the outermost#ifndef
encloses the entire file and notes what macro it checks may be able to avoid rescanning the file, but a directive to say there's nothing of importance following the current point would seem seem nicer than relying upon compilers to remember such things.
– supercat
Nov 22 at 6:47
|
show 8 more comments
up vote
61
down vote
accepted
up vote
61
down vote
accepted
There are multiple related questions here:
Why is
#pragma once
not automatically enforced?
Because there are situations in which you want to include files more than once.Why would you want to include a file multiple times?
Several reasons have been given in other answers (Boost.Preprocessor, X-Macros, including data files). I would like to add a particular example of "avoid code duplication": OpenFOAM encourages a style where#include
ing bits and pieces within functions is a common concept. See for example this discussion.Ok, but why is it not the default with an opt-out?
Because it is not actually specified by the standard.#pragma
s are by definition implementation-specific extensions.Why has
#pragma once
not become a standardized feature yet (as it is widely supported)?
Because pinning down what is "the same file" in a platform-agnostic way is actually surprisingly hard. See this answer for more information.
There are multiple related questions here:
Why is
#pragma once
not automatically enforced?
Because there are situations in which you want to include files more than once.Why would you want to include a file multiple times?
Several reasons have been given in other answers (Boost.Preprocessor, X-Macros, including data files). I would like to add a particular example of "avoid code duplication": OpenFOAM encourages a style where#include
ing bits and pieces within functions is a common concept. See for example this discussion.Ok, but why is it not the default with an opt-out?
Because it is not actually specified by the standard.#pragma
s are by definition implementation-specific extensions.Why has
#pragma once
not become a standardized feature yet (as it is widely supported)?
Because pinning down what is "the same file" in a platform-agnostic way is actually surprisingly hard. See this answer for more information.
edited Nov 21 at 17:46
answered Nov 21 at 17:41
Max Langhof
7,4781233
7,4781233
And another take on why not standardizeonce
– user4581301
Nov 21 at 19:05
4
In particular, see this example for a case of wherepragma once
fails but include guards would have worked. Identifying files by location doesn't work either because sometimes the same file occurs multiple times in a project (e.g. you have 2 submodules that both include a header-only library in their headers and check out their own copy of it)
– M.M
Nov 21 at 19:46
4
Not all pragmas are implementation-specific extensions. E.g.#pragma STDC
family. But they all do control implementation-defined behavior.
– Ruslan
Nov 21 at 20:58
2
@user4581301 This answer over exaggerates the problem with pragma once and does not consider troubles due to include guards. In both case some discipline is needed. With include guards one must make sure to use a name that will not be used in an other file (which will happen after a file copy modify). With pragma once, one has to decide what is the unique right place for its file, which is a good thing after all.
– Oliv
Nov 21 at 22:42
3
@Mehrdad: Are you seriously suggesting that compilers write to source files!? If a compiler sees#ifndef XX
, it must can't know whether there's anything following the corresponding#endif
until it's read the entire file. A compiler that keeps track of whether the outermost#ifndef
encloses the entire file and notes what macro it checks may be able to avoid rescanning the file, but a directive to say there's nothing of importance following the current point would seem seem nicer than relying upon compilers to remember such things.
– supercat
Nov 22 at 6:47
|
show 8 more comments
And another take on why not standardizeonce
– user4581301
Nov 21 at 19:05
4
In particular, see this example for a case of wherepragma once
fails but include guards would have worked. Identifying files by location doesn't work either because sometimes the same file occurs multiple times in a project (e.g. you have 2 submodules that both include a header-only library in their headers and check out their own copy of it)
– M.M
Nov 21 at 19:46
4
Not all pragmas are implementation-specific extensions. E.g.#pragma STDC
family. But they all do control implementation-defined behavior.
– Ruslan
Nov 21 at 20:58
2
@user4581301 This answer over exaggerates the problem with pragma once and does not consider troubles due to include guards. In both case some discipline is needed. With include guards one must make sure to use a name that will not be used in an other file (which will happen after a file copy modify). With pragma once, one has to decide what is the unique right place for its file, which is a good thing after all.
– Oliv
Nov 21 at 22:42
3
@Mehrdad: Are you seriously suggesting that compilers write to source files!? If a compiler sees#ifndef XX
, it must can't know whether there's anything following the corresponding#endif
until it's read the entire file. A compiler that keeps track of whether the outermost#ifndef
encloses the entire file and notes what macro it checks may be able to avoid rescanning the file, but a directive to say there's nothing of importance following the current point would seem seem nicer than relying upon compilers to remember such things.
– supercat
Nov 22 at 6:47
And another take on why not standardize
once
– user4581301
Nov 21 at 19:05
And another take on why not standardize
once
– user4581301
Nov 21 at 19:05
4
4
In particular, see this example for a case of where
pragma once
fails but include guards would have worked. Identifying files by location doesn't work either because sometimes the same file occurs multiple times in a project (e.g. you have 2 submodules that both include a header-only library in their headers and check out their own copy of it)– M.M
Nov 21 at 19:46
In particular, see this example for a case of where
pragma once
fails but include guards would have worked. Identifying files by location doesn't work either because sometimes the same file occurs multiple times in a project (e.g. you have 2 submodules that both include a header-only library in their headers and check out their own copy of it)– M.M
Nov 21 at 19:46
4
4
Not all pragmas are implementation-specific extensions. E.g.
#pragma STDC
family. But they all do control implementation-defined behavior.– Ruslan
Nov 21 at 20:58
Not all pragmas are implementation-specific extensions. E.g.
#pragma STDC
family. But they all do control implementation-defined behavior.– Ruslan
Nov 21 at 20:58
2
2
@user4581301 This answer over exaggerates the problem with pragma once and does not consider troubles due to include guards. In both case some discipline is needed. With include guards one must make sure to use a name that will not be used in an other file (which will happen after a file copy modify). With pragma once, one has to decide what is the unique right place for its file, which is a good thing after all.
– Oliv
Nov 21 at 22:42
@user4581301 This answer over exaggerates the problem with pragma once and does not consider troubles due to include guards. In both case some discipline is needed. With include guards one must make sure to use a name that will not be used in an other file (which will happen after a file copy modify). With pragma once, one has to decide what is the unique right place for its file, which is a good thing after all.
– Oliv
Nov 21 at 22:42
3
3
@Mehrdad: Are you seriously suggesting that compilers write to source files!? If a compiler sees
#ifndef XX
, it must can't know whether there's anything following the corresponding #endif
until it's read the entire file. A compiler that keeps track of whether the outermost #ifndef
encloses the entire file and notes what macro it checks may be able to avoid rescanning the file, but a directive to say there's nothing of importance following the current point would seem seem nicer than relying upon compilers to remember such things.– supercat
Nov 22 at 6:47
@Mehrdad: Are you seriously suggesting that compilers write to source files!? If a compiler sees
#ifndef XX
, it must can't know whether there's anything following the corresponding #endif
until it's read the entire file. A compiler that keeps track of whether the outermost #ifndef
encloses the entire file and notes what macro it checks may be able to avoid rescanning the file, but a directive to say there's nothing of importance following the current point would seem seem nicer than relying upon compilers to remember such things.– supercat
Nov 22 at 6:47
|
show 8 more comments
up vote
31
down vote
You can use #include
anywhere in a file, not just at global scope - like, inside a function (and multiple times if needed). Sure, ugly and not good style, but possible and occasionally sensible (depending on the file you include). If #include
was only ever a one time thing then that wouldn't work. #include
just does dumb text substitution (cut'n'paste) after all, and not everything you include has to be a header file. You might - for example - #include
a file containing auto generated data containing the raw data to initialize a std::vector
. Like
std::vector<int> data = {
#include "my_generated_data.txt"
}
And have "my_generated_data.txt" be something generated by the build system during compilation.
Or maybe I'm lazy/silly/stupid and put this in a file (very contrived example):
const noexcept;
and then I do
class foo {
void f1()
#include "stupid.file"
int f2(int)
#include "stupid.file"
};
Another, slightly less contrived, example would be a source file where many functions need to use a large amount of types in a namespace, but you don't want to just say using namespace foo;
globally since that would polute the global namespace with a lot of other stuff you don't want. So you create a file "foo" containing
using std::vector;
using std::array;
using std::rotate;
... You get the idea ...
And then you do this in your source file
void f1() {
#include "foo" // needs "stuff"
}
void f2() {
// Doesn't need "stuff"
}
void f3() {
#include "foo" // also needs "stuff"
}
Note: I'm not advocating doing things like this. But it is possible and done in some codebases and I don't see why it should not be allowed. It does have its uses.
It could also be that the file you include behaves differently depending on the value of certain macros (#define
s). So you may want to include the file in multiple locations, after first having changed some value, so you get different behaviour in different parts of your source file.
This would still work if all headers were pragma once. As long as you didn't include the generated data more than once.
– PSkocik
Nov 21 at 16:57
1
@PSkocik But maybe I need to include it more than once. Why shouldn't I be able to?
– Jesper Juhl
Nov 21 at 16:59
1
@JesperJuhl That's the point. You won't need to include it more than once ever. You currently have the option, but the alternative isn't much worse, if at all.
– Johnny Cache
Nov 21 at 17:08
8
@PSkocik If I change the value of#define
s before each include that changes the behaviour of the included file then I may very well need to include it multiple times to get those different behaviours in different parts of my source file.
– Jesper Juhl
Nov 21 at 17:28
add a comment |
up vote
31
down vote
You can use #include
anywhere in a file, not just at global scope - like, inside a function (and multiple times if needed). Sure, ugly and not good style, but possible and occasionally sensible (depending on the file you include). If #include
was only ever a one time thing then that wouldn't work. #include
just does dumb text substitution (cut'n'paste) after all, and not everything you include has to be a header file. You might - for example - #include
a file containing auto generated data containing the raw data to initialize a std::vector
. Like
std::vector<int> data = {
#include "my_generated_data.txt"
}
And have "my_generated_data.txt" be something generated by the build system during compilation.
Or maybe I'm lazy/silly/stupid and put this in a file (very contrived example):
const noexcept;
and then I do
class foo {
void f1()
#include "stupid.file"
int f2(int)
#include "stupid.file"
};
Another, slightly less contrived, example would be a source file where many functions need to use a large amount of types in a namespace, but you don't want to just say using namespace foo;
globally since that would polute the global namespace with a lot of other stuff you don't want. So you create a file "foo" containing
using std::vector;
using std::array;
using std::rotate;
... You get the idea ...
And then you do this in your source file
void f1() {
#include "foo" // needs "stuff"
}
void f2() {
// Doesn't need "stuff"
}
void f3() {
#include "foo" // also needs "stuff"
}
Note: I'm not advocating doing things like this. But it is possible and done in some codebases and I don't see why it should not be allowed. It does have its uses.
It could also be that the file you include behaves differently depending on the value of certain macros (#define
s). So you may want to include the file in multiple locations, after first having changed some value, so you get different behaviour in different parts of your source file.
This would still work if all headers were pragma once. As long as you didn't include the generated data more than once.
– PSkocik
Nov 21 at 16:57
1
@PSkocik But maybe I need to include it more than once. Why shouldn't I be able to?
– Jesper Juhl
Nov 21 at 16:59
1
@JesperJuhl That's the point. You won't need to include it more than once ever. You currently have the option, but the alternative isn't much worse, if at all.
– Johnny Cache
Nov 21 at 17:08
8
@PSkocik If I change the value of#define
s before each include that changes the behaviour of the included file then I may very well need to include it multiple times to get those different behaviours in different parts of my source file.
– Jesper Juhl
Nov 21 at 17:28
add a comment |
up vote
31
down vote
up vote
31
down vote
You can use #include
anywhere in a file, not just at global scope - like, inside a function (and multiple times if needed). Sure, ugly and not good style, but possible and occasionally sensible (depending on the file you include). If #include
was only ever a one time thing then that wouldn't work. #include
just does dumb text substitution (cut'n'paste) after all, and not everything you include has to be a header file. You might - for example - #include
a file containing auto generated data containing the raw data to initialize a std::vector
. Like
std::vector<int> data = {
#include "my_generated_data.txt"
}
And have "my_generated_data.txt" be something generated by the build system during compilation.
Or maybe I'm lazy/silly/stupid and put this in a file (very contrived example):
const noexcept;
and then I do
class foo {
void f1()
#include "stupid.file"
int f2(int)
#include "stupid.file"
};
Another, slightly less contrived, example would be a source file where many functions need to use a large amount of types in a namespace, but you don't want to just say using namespace foo;
globally since that would polute the global namespace with a lot of other stuff you don't want. So you create a file "foo" containing
using std::vector;
using std::array;
using std::rotate;
... You get the idea ...
And then you do this in your source file
void f1() {
#include "foo" // needs "stuff"
}
void f2() {
// Doesn't need "stuff"
}
void f3() {
#include "foo" // also needs "stuff"
}
Note: I'm not advocating doing things like this. But it is possible and done in some codebases and I don't see why it should not be allowed. It does have its uses.
It could also be that the file you include behaves differently depending on the value of certain macros (#define
s). So you may want to include the file in multiple locations, after first having changed some value, so you get different behaviour in different parts of your source file.
You can use #include
anywhere in a file, not just at global scope - like, inside a function (and multiple times if needed). Sure, ugly and not good style, but possible and occasionally sensible (depending on the file you include). If #include
was only ever a one time thing then that wouldn't work. #include
just does dumb text substitution (cut'n'paste) after all, and not everything you include has to be a header file. You might - for example - #include
a file containing auto generated data containing the raw data to initialize a std::vector
. Like
std::vector<int> data = {
#include "my_generated_data.txt"
}
And have "my_generated_data.txt" be something generated by the build system during compilation.
Or maybe I'm lazy/silly/stupid and put this in a file (very contrived example):
const noexcept;
and then I do
class foo {
void f1()
#include "stupid.file"
int f2(int)
#include "stupid.file"
};
Another, slightly less contrived, example would be a source file where many functions need to use a large amount of types in a namespace, but you don't want to just say using namespace foo;
globally since that would polute the global namespace with a lot of other stuff you don't want. So you create a file "foo" containing
using std::vector;
using std::array;
using std::rotate;
... You get the idea ...
And then you do this in your source file
void f1() {
#include "foo" // needs "stuff"
}
void f2() {
// Doesn't need "stuff"
}
void f3() {
#include "foo" // also needs "stuff"
}
Note: I'm not advocating doing things like this. But it is possible and done in some codebases and I don't see why it should not be allowed. It does have its uses.
It could also be that the file you include behaves differently depending on the value of certain macros (#define
s). So you may want to include the file in multiple locations, after first having changed some value, so you get different behaviour in different parts of your source file.
edited Nov 22 at 17:54
answered Nov 21 at 16:54
Jesper Juhl
15.6k32244
15.6k32244
This would still work if all headers were pragma once. As long as you didn't include the generated data more than once.
– PSkocik
Nov 21 at 16:57
1
@PSkocik But maybe I need to include it more than once. Why shouldn't I be able to?
– Jesper Juhl
Nov 21 at 16:59
1
@JesperJuhl That's the point. You won't need to include it more than once ever. You currently have the option, but the alternative isn't much worse, if at all.
– Johnny Cache
Nov 21 at 17:08
8
@PSkocik If I change the value of#define
s before each include that changes the behaviour of the included file then I may very well need to include it multiple times to get those different behaviours in different parts of my source file.
– Jesper Juhl
Nov 21 at 17:28
add a comment |
This would still work if all headers were pragma once. As long as you didn't include the generated data more than once.
– PSkocik
Nov 21 at 16:57
1
@PSkocik But maybe I need to include it more than once. Why shouldn't I be able to?
– Jesper Juhl
Nov 21 at 16:59
1
@JesperJuhl That's the point. You won't need to include it more than once ever. You currently have the option, but the alternative isn't much worse, if at all.
– Johnny Cache
Nov 21 at 17:08
8
@PSkocik If I change the value of#define
s before each include that changes the behaviour of the included file then I may very well need to include it multiple times to get those different behaviours in different parts of my source file.
– Jesper Juhl
Nov 21 at 17:28
This would still work if all headers were pragma once. As long as you didn't include the generated data more than once.
– PSkocik
Nov 21 at 16:57
This would still work if all headers were pragma once. As long as you didn't include the generated data more than once.
– PSkocik
Nov 21 at 16:57
1
1
@PSkocik But maybe I need to include it more than once. Why shouldn't I be able to?
– Jesper Juhl
Nov 21 at 16:59
@PSkocik But maybe I need to include it more than once. Why shouldn't I be able to?
– Jesper Juhl
Nov 21 at 16:59
1
1
@JesperJuhl That's the point. You won't need to include it more than once ever. You currently have the option, but the alternative isn't much worse, if at all.
– Johnny Cache
Nov 21 at 17:08
@JesperJuhl That's the point. You won't need to include it more than once ever. You currently have the option, but the alternative isn't much worse, if at all.
– Johnny Cache
Nov 21 at 17:08
8
8
@PSkocik If I change the value of
#define
s before each include that changes the behaviour of the included file then I may very well need to include it multiple times to get those different behaviours in different parts of my source file.– Jesper Juhl
Nov 21 at 17:28
@PSkocik If I change the value of
#define
s before each include that changes the behaviour of the included file then I may very well need to include it multiple times to get those different behaviours in different parts of my source file.– Jesper Juhl
Nov 21 at 17:28
add a comment |
up vote
21
down vote
Including multiple times is usable e.g., with the X-macro technique:
data.inc:
X(ONE)
X(TWO)
X(THREE)
use_data_inc_twice.c
enum data_e {
#define X(V) V,
#include "data.inc"
#undef X
};
char const* data_e__strings={
#define X(V) [V]=#V,
#include "data.inc"
#undef X
};
I don't know about any other use.
That sounds overly complex. Any reason not to just include those definitions in the file in the first place?
– Johnny Cache
Nov 21 at 16:50
2
@JohnnyCache: The example is a simplified version of how X-macros work. Please read the link; they're extremely useful in some cases for doing complex manipulations of tabular data. In any significant usage of X-macros, there would be no way you could just "include those definitions in the file".
– Nicol Bolas
Nov 21 at 16:51
2
@Johnny - yes - one good reason is to ensure consistency (hard to do by hand when you have just a few dozen elements, never mind hundreds).
– Toby Speight
Nov 21 at 16:51
@TobySpeight Heh, I suppose I could spare a single line of code to avoid writing thousands somewhere else. Makes sense.
– Johnny Cache
Nov 21 at 16:52
1
To avoid duplication. Especially if the file is large. Admittedly, you could just use a big macro containing the X macro list but since projects could be using this, mandating#pragma once
behavior would be a breaking change.
– PSkocik
Nov 21 at 16:52
|
show 2 more comments
up vote
21
down vote
Including multiple times is usable e.g., with the X-macro technique:
data.inc:
X(ONE)
X(TWO)
X(THREE)
use_data_inc_twice.c
enum data_e {
#define X(V) V,
#include "data.inc"
#undef X
};
char const* data_e__strings={
#define X(V) [V]=#V,
#include "data.inc"
#undef X
};
I don't know about any other use.
That sounds overly complex. Any reason not to just include those definitions in the file in the first place?
– Johnny Cache
Nov 21 at 16:50
2
@JohnnyCache: The example is a simplified version of how X-macros work. Please read the link; they're extremely useful in some cases for doing complex manipulations of tabular data. In any significant usage of X-macros, there would be no way you could just "include those definitions in the file".
– Nicol Bolas
Nov 21 at 16:51
2
@Johnny - yes - one good reason is to ensure consistency (hard to do by hand when you have just a few dozen elements, never mind hundreds).
– Toby Speight
Nov 21 at 16:51
@TobySpeight Heh, I suppose I could spare a single line of code to avoid writing thousands somewhere else. Makes sense.
– Johnny Cache
Nov 21 at 16:52
1
To avoid duplication. Especially if the file is large. Admittedly, you could just use a big macro containing the X macro list but since projects could be using this, mandating#pragma once
behavior would be a breaking change.
– PSkocik
Nov 21 at 16:52
|
show 2 more comments
up vote
21
down vote
up vote
21
down vote
Including multiple times is usable e.g., with the X-macro technique:
data.inc:
X(ONE)
X(TWO)
X(THREE)
use_data_inc_twice.c
enum data_e {
#define X(V) V,
#include "data.inc"
#undef X
};
char const* data_e__strings={
#define X(V) [V]=#V,
#include "data.inc"
#undef X
};
I don't know about any other use.
Including multiple times is usable e.g., with the X-macro technique:
data.inc:
X(ONE)
X(TWO)
X(THREE)
use_data_inc_twice.c
enum data_e {
#define X(V) V,
#include "data.inc"
#undef X
};
char const* data_e__strings={
#define X(V) [V]=#V,
#include "data.inc"
#undef X
};
I don't know about any other use.
edited Nov 21 at 16:59
answered Nov 21 at 16:48
PSkocik
31.5k54569
31.5k54569
That sounds overly complex. Any reason not to just include those definitions in the file in the first place?
– Johnny Cache
Nov 21 at 16:50
2
@JohnnyCache: The example is a simplified version of how X-macros work. Please read the link; they're extremely useful in some cases for doing complex manipulations of tabular data. In any significant usage of X-macros, there would be no way you could just "include those definitions in the file".
– Nicol Bolas
Nov 21 at 16:51
2
@Johnny - yes - one good reason is to ensure consistency (hard to do by hand when you have just a few dozen elements, never mind hundreds).
– Toby Speight
Nov 21 at 16:51
@TobySpeight Heh, I suppose I could spare a single line of code to avoid writing thousands somewhere else. Makes sense.
– Johnny Cache
Nov 21 at 16:52
1
To avoid duplication. Especially if the file is large. Admittedly, you could just use a big macro containing the X macro list but since projects could be using this, mandating#pragma once
behavior would be a breaking change.
– PSkocik
Nov 21 at 16:52
|
show 2 more comments
That sounds overly complex. Any reason not to just include those definitions in the file in the first place?
– Johnny Cache
Nov 21 at 16:50
2
@JohnnyCache: The example is a simplified version of how X-macros work. Please read the link; they're extremely useful in some cases for doing complex manipulations of tabular data. In any significant usage of X-macros, there would be no way you could just "include those definitions in the file".
– Nicol Bolas
Nov 21 at 16:51
2
@Johnny - yes - one good reason is to ensure consistency (hard to do by hand when you have just a few dozen elements, never mind hundreds).
– Toby Speight
Nov 21 at 16:51
@TobySpeight Heh, I suppose I could spare a single line of code to avoid writing thousands somewhere else. Makes sense.
– Johnny Cache
Nov 21 at 16:52
1
To avoid duplication. Especially if the file is large. Admittedly, you could just use a big macro containing the X macro list but since projects could be using this, mandating#pragma once
behavior would be a breaking change.
– PSkocik
Nov 21 at 16:52
That sounds overly complex. Any reason not to just include those definitions in the file in the first place?
– Johnny Cache
Nov 21 at 16:50
That sounds overly complex. Any reason not to just include those definitions in the file in the first place?
– Johnny Cache
Nov 21 at 16:50
2
2
@JohnnyCache: The example is a simplified version of how X-macros work. Please read the link; they're extremely useful in some cases for doing complex manipulations of tabular data. In any significant usage of X-macros, there would be no way you could just "include those definitions in the file".
– Nicol Bolas
Nov 21 at 16:51
@JohnnyCache: The example is a simplified version of how X-macros work. Please read the link; they're extremely useful in some cases for doing complex manipulations of tabular data. In any significant usage of X-macros, there would be no way you could just "include those definitions in the file".
– Nicol Bolas
Nov 21 at 16:51
2
2
@Johnny - yes - one good reason is to ensure consistency (hard to do by hand when you have just a few dozen elements, never mind hundreds).
– Toby Speight
Nov 21 at 16:51
@Johnny - yes - one good reason is to ensure consistency (hard to do by hand when you have just a few dozen elements, never mind hundreds).
– Toby Speight
Nov 21 at 16:51
@TobySpeight Heh, I suppose I could spare a single line of code to avoid writing thousands somewhere else. Makes sense.
– Johnny Cache
Nov 21 at 16:52
@TobySpeight Heh, I suppose I could spare a single line of code to avoid writing thousands somewhere else. Makes sense.
– Johnny Cache
Nov 21 at 16:52
1
1
To avoid duplication. Especially if the file is large. Admittedly, you could just use a big macro containing the X macro list but since projects could be using this, mandating
#pragma once
behavior would be a breaking change.– PSkocik
Nov 21 at 16:52
To avoid duplication. Especially if the file is large. Admittedly, you could just use a big macro containing the X macro list but since projects could be using this, mandating
#pragma once
behavior would be a breaking change.– PSkocik
Nov 21 at 16:52
|
show 2 more comments
up vote
15
down vote
You seem to be operating under the assumption that the purpose of the "#include" feature even existing in the language is to provide support for decomposition of programs into multiple compilation units. That is incorrect.
It can perform that role, but that was not its intended purpose. C was originally developed as slightly higher-level language than PDP-11 Macro-11 Assembly for reimplementing Unix. It had a macro preprocessor because that was a feature of Macro-11. It had the ability to textually include macros from another file because that was a feature of Macro-11 that the existing Unix they were porting to their new C compiler had made use of.
Now it turns out that "#include" is useful for separating code into compilation units, as (arguably) a bit of a hack. However, the fact that this hack existed meant that it became The Way that is done in C. The fact that a way existed meant no new method ever needed to be created to provide this functionality, so nothing safer (eg: not vulnerable to multiple-inclusion) was ever created. Since it was already in C, it got copied into C++ along with most of the rest of C's syntax and idioms.
There is a proposal for giving C++ a proper module system so this 45 year old preprocessor hack can finally be dispensed with. I don't know how imminent this is though. I've been hearing about it being in the works for more than a decade.
2
As usual, to understand C and C++, you need to understand their history.
– Jack Aidley
Nov 22 at 12:27
It is reasonable to expect that modules will land in February.
– Davis Herring
Nov 22 at 20:31
3
@DavisHerring - Yes, but which February?
– T.E.D.
Nov 23 at 0:02
add a comment |
up vote
15
down vote
You seem to be operating under the assumption that the purpose of the "#include" feature even existing in the language is to provide support for decomposition of programs into multiple compilation units. That is incorrect.
It can perform that role, but that was not its intended purpose. C was originally developed as slightly higher-level language than PDP-11 Macro-11 Assembly for reimplementing Unix. It had a macro preprocessor because that was a feature of Macro-11. It had the ability to textually include macros from another file because that was a feature of Macro-11 that the existing Unix they were porting to their new C compiler had made use of.
Now it turns out that "#include" is useful for separating code into compilation units, as (arguably) a bit of a hack. However, the fact that this hack existed meant that it became The Way that is done in C. The fact that a way existed meant no new method ever needed to be created to provide this functionality, so nothing safer (eg: not vulnerable to multiple-inclusion) was ever created. Since it was already in C, it got copied into C++ along with most of the rest of C's syntax and idioms.
There is a proposal for giving C++ a proper module system so this 45 year old preprocessor hack can finally be dispensed with. I don't know how imminent this is though. I've been hearing about it being in the works for more than a decade.
2
As usual, to understand C and C++, you need to understand their history.
– Jack Aidley
Nov 22 at 12:27
It is reasonable to expect that modules will land in February.
– Davis Herring
Nov 22 at 20:31
3
@DavisHerring - Yes, but which February?
– T.E.D.
Nov 23 at 0:02
add a comment |
up vote
15
down vote
up vote
15
down vote
You seem to be operating under the assumption that the purpose of the "#include" feature even existing in the language is to provide support for decomposition of programs into multiple compilation units. That is incorrect.
It can perform that role, but that was not its intended purpose. C was originally developed as slightly higher-level language than PDP-11 Macro-11 Assembly for reimplementing Unix. It had a macro preprocessor because that was a feature of Macro-11. It had the ability to textually include macros from another file because that was a feature of Macro-11 that the existing Unix they were porting to their new C compiler had made use of.
Now it turns out that "#include" is useful for separating code into compilation units, as (arguably) a bit of a hack. However, the fact that this hack existed meant that it became The Way that is done in C. The fact that a way existed meant no new method ever needed to be created to provide this functionality, so nothing safer (eg: not vulnerable to multiple-inclusion) was ever created. Since it was already in C, it got copied into C++ along with most of the rest of C's syntax and idioms.
There is a proposal for giving C++ a proper module system so this 45 year old preprocessor hack can finally be dispensed with. I don't know how imminent this is though. I've been hearing about it being in the works for more than a decade.
You seem to be operating under the assumption that the purpose of the "#include" feature even existing in the language is to provide support for decomposition of programs into multiple compilation units. That is incorrect.
It can perform that role, but that was not its intended purpose. C was originally developed as slightly higher-level language than PDP-11 Macro-11 Assembly for reimplementing Unix. It had a macro preprocessor because that was a feature of Macro-11. It had the ability to textually include macros from another file because that was a feature of Macro-11 that the existing Unix they were porting to their new C compiler had made use of.
Now it turns out that "#include" is useful for separating code into compilation units, as (arguably) a bit of a hack. However, the fact that this hack existed meant that it became The Way that is done in C. The fact that a way existed meant no new method ever needed to be created to provide this functionality, so nothing safer (eg: not vulnerable to multiple-inclusion) was ever created. Since it was already in C, it got copied into C++ along with most of the rest of C's syntax and idioms.
There is a proposal for giving C++ a proper module system so this 45 year old preprocessor hack can finally be dispensed with. I don't know how imminent this is though. I've been hearing about it being in the works for more than a decade.
answered Nov 21 at 20:18
T.E.D.
35.6k757126
35.6k757126
2
As usual, to understand C and C++, you need to understand their history.
– Jack Aidley
Nov 22 at 12:27
It is reasonable to expect that modules will land in February.
– Davis Herring
Nov 22 at 20:31
3
@DavisHerring - Yes, but which February?
– T.E.D.
Nov 23 at 0:02
add a comment |
2
As usual, to understand C and C++, you need to understand their history.
– Jack Aidley
Nov 22 at 12:27
It is reasonable to expect that modules will land in February.
– Davis Herring
Nov 22 at 20:31
3
@DavisHerring - Yes, but which February?
– T.E.D.
Nov 23 at 0:02
2
2
As usual, to understand C and C++, you need to understand their history.
– Jack Aidley
Nov 22 at 12:27
As usual, to understand C and C++, you need to understand their history.
– Jack Aidley
Nov 22 at 12:27
It is reasonable to expect that modules will land in February.
– Davis Herring
Nov 22 at 20:31
It is reasonable to expect that modules will land in February.
– Davis Herring
Nov 22 at 20:31
3
3
@DavisHerring - Yes, but which February?
– T.E.D.
Nov 23 at 0:02
@DavisHerring - Yes, but which February?
– T.E.D.
Nov 23 at 0:02
add a comment |
up vote
9
down vote
No, this would significantly hinder the options available to, for example, library writers. For example, Boost.Preprocessor allows one to use pre-processor loops, and the only way to achieve those is by multiple inclusions of the same file.
And Boost.Preprocessor is a building block for many very useful libraries.
1
It would not hinder any of that. OP asked about a default behaviour, not an unchangeable behaviour. It would be entirely sensible to change the default and instead provide a preprocessor flag#pragma reentrant
or something along these lines. Hindsight is 20/20.
– Konrad Rudolph
Nov 23 at 11:12
It would hinder it in the sense of forcing people to update their libraries and dependencies, @KonradRudolph. Not always a problem, but it could cause issues with some legacy programs. Ideally, there would also be a command-line switch to specify whether the default isonce
orreentrant
, to mitigate this or other potential issues.
– Justin Time
yesterday
@JustinTime Well as my comment says it’s clearly not a backwards compatible (and therefore feasible) change. The question, however, was why it was initially designed that way, not why it’s not being changed. And the answer to that is, unambiguously, that the original design was a huge mistake with far-reaching consequences.
– Konrad Rudolph
21 hours ago
add a comment |
up vote
9
down vote
No, this would significantly hinder the options available to, for example, library writers. For example, Boost.Preprocessor allows one to use pre-processor loops, and the only way to achieve those is by multiple inclusions of the same file.
And Boost.Preprocessor is a building block for many very useful libraries.
1
It would not hinder any of that. OP asked about a default behaviour, not an unchangeable behaviour. It would be entirely sensible to change the default and instead provide a preprocessor flag#pragma reentrant
or something along these lines. Hindsight is 20/20.
– Konrad Rudolph
Nov 23 at 11:12
It would hinder it in the sense of forcing people to update their libraries and dependencies, @KonradRudolph. Not always a problem, but it could cause issues with some legacy programs. Ideally, there would also be a command-line switch to specify whether the default isonce
orreentrant
, to mitigate this or other potential issues.
– Justin Time
yesterday
@JustinTime Well as my comment says it’s clearly not a backwards compatible (and therefore feasible) change. The question, however, was why it was initially designed that way, not why it’s not being changed. And the answer to that is, unambiguously, that the original design was a huge mistake with far-reaching consequences.
– Konrad Rudolph
21 hours ago
add a comment |
up vote
9
down vote
up vote
9
down vote
No, this would significantly hinder the options available to, for example, library writers. For example, Boost.Preprocessor allows one to use pre-processor loops, and the only way to achieve those is by multiple inclusions of the same file.
And Boost.Preprocessor is a building block for many very useful libraries.
No, this would significantly hinder the options available to, for example, library writers. For example, Boost.Preprocessor allows one to use pre-processor loops, and the only way to achieve those is by multiple inclusions of the same file.
And Boost.Preprocessor is a building block for many very useful libraries.
answered Nov 21 at 17:06
SergeyA
40.4k53781
40.4k53781
1
It would not hinder any of that. OP asked about a default behaviour, not an unchangeable behaviour. It would be entirely sensible to change the default and instead provide a preprocessor flag#pragma reentrant
or something along these lines. Hindsight is 20/20.
– Konrad Rudolph
Nov 23 at 11:12
It would hinder it in the sense of forcing people to update their libraries and dependencies, @KonradRudolph. Not always a problem, but it could cause issues with some legacy programs. Ideally, there would also be a command-line switch to specify whether the default isonce
orreentrant
, to mitigate this or other potential issues.
– Justin Time
yesterday
@JustinTime Well as my comment says it’s clearly not a backwards compatible (and therefore feasible) change. The question, however, was why it was initially designed that way, not why it’s not being changed. And the answer to that is, unambiguously, that the original design was a huge mistake with far-reaching consequences.
– Konrad Rudolph
21 hours ago
add a comment |
1
It would not hinder any of that. OP asked about a default behaviour, not an unchangeable behaviour. It would be entirely sensible to change the default and instead provide a preprocessor flag#pragma reentrant
or something along these lines. Hindsight is 20/20.
– Konrad Rudolph
Nov 23 at 11:12
It would hinder it in the sense of forcing people to update their libraries and dependencies, @KonradRudolph. Not always a problem, but it could cause issues with some legacy programs. Ideally, there would also be a command-line switch to specify whether the default isonce
orreentrant
, to mitigate this or other potential issues.
– Justin Time
yesterday
@JustinTime Well as my comment says it’s clearly not a backwards compatible (and therefore feasible) change. The question, however, was why it was initially designed that way, not why it’s not being changed. And the answer to that is, unambiguously, that the original design was a huge mistake with far-reaching consequences.
– Konrad Rudolph
21 hours ago
1
1
It would not hinder any of that. OP asked about a default behaviour, not an unchangeable behaviour. It would be entirely sensible to change the default and instead provide a preprocessor flag
#pragma reentrant
or something along these lines. Hindsight is 20/20.– Konrad Rudolph
Nov 23 at 11:12
It would not hinder any of that. OP asked about a default behaviour, not an unchangeable behaviour. It would be entirely sensible to change the default and instead provide a preprocessor flag
#pragma reentrant
or something along these lines. Hindsight is 20/20.– Konrad Rudolph
Nov 23 at 11:12
It would hinder it in the sense of forcing people to update their libraries and dependencies, @KonradRudolph. Not always a problem, but it could cause issues with some legacy programs. Ideally, there would also be a command-line switch to specify whether the default is
once
or reentrant
, to mitigate this or other potential issues.– Justin Time
yesterday
It would hinder it in the sense of forcing people to update their libraries and dependencies, @KonradRudolph. Not always a problem, but it could cause issues with some legacy programs. Ideally, there would also be a command-line switch to specify whether the default is
once
or reentrant
, to mitigate this or other potential issues.– Justin Time
yesterday
@JustinTime Well as my comment says it’s clearly not a backwards compatible (and therefore feasible) change. The question, however, was why it was initially designed that way, not why it’s not being changed. And the answer to that is, unambiguously, that the original design was a huge mistake with far-reaching consequences.
– Konrad Rudolph
21 hours ago
@JustinTime Well as my comment says it’s clearly not a backwards compatible (and therefore feasible) change. The question, however, was why it was initially designed that way, not why it’s not being changed. And the answer to that is, unambiguously, that the original design was a huge mistake with far-reaching consequences.
– Konrad Rudolph
21 hours ago
add a comment |
up vote
7
down vote
In the firmware for the product I mainly work on, we need to be able to specify where functions and global/static variables should be allocated in memory. Real-time processing needs to live in L1 memory on chip so the processor can access it directly, fast. Less important processing can go in L2 memory on chip. And anything that doesn't need to be handled particularly promptly can live in the external DDR and go through caching, because it doesn't matter if it's a little slower.
The #pragma to allocate where things go is a long, non-trivial line. It'd be easy to get it wrong. The effect of getting it wrong would be that the code/data would be silently put into default (DDR) memory, and the effect of that might be closed-loop control stopping working for no reason that's easy to see.
So I use include files, which contain just that pragma. My code now looks like this.
Header file...
#ifndef HEADERFILE_H
#define HEADERFILE_H
#include "set_fast_storage.h"
/* Declare variables */
#include "set_slow_storage.h"
/* Declare functions for initialisation on startup */
#include "set_fast_storage.h"
/* Declare functions for real-time processing */
#include "set_storage_default.h"
#endif
And source...
#include "headerfile.h"
#include "set_fast_storage.h"
/* Define variables */
#include "set_slow_storage.h"
/* Define functions for initialisation on startup */
#include "set_fast_storage.h"
/* Define functions for real-time processing */
You'll notice multiple inclusions of the same file there, even just in the header. If I mistype something now, the compiler will tell me it can't find the include file "set_fat_storage.h" and I can easily fix it.
So in answer to your question, this is a real, practical example of where multiple inclusion is required.
3
I would say your use case is a motivating example for the_Pragma
directive. The same pragmas can now be expanded from regular macros. So no need to include more than once.
– StoryTeller
Nov 22 at 4:13
@StoryTeller Good point, I could do.
– Graham
Nov 22 at 15:35
add a comment |
up vote
7
down vote
In the firmware for the product I mainly work on, we need to be able to specify where functions and global/static variables should be allocated in memory. Real-time processing needs to live in L1 memory on chip so the processor can access it directly, fast. Less important processing can go in L2 memory on chip. And anything that doesn't need to be handled particularly promptly can live in the external DDR and go through caching, because it doesn't matter if it's a little slower.
The #pragma to allocate where things go is a long, non-trivial line. It'd be easy to get it wrong. The effect of getting it wrong would be that the code/data would be silently put into default (DDR) memory, and the effect of that might be closed-loop control stopping working for no reason that's easy to see.
So I use include files, which contain just that pragma. My code now looks like this.
Header file...
#ifndef HEADERFILE_H
#define HEADERFILE_H
#include "set_fast_storage.h"
/* Declare variables */
#include "set_slow_storage.h"
/* Declare functions for initialisation on startup */
#include "set_fast_storage.h"
/* Declare functions for real-time processing */
#include "set_storage_default.h"
#endif
And source...
#include "headerfile.h"
#include "set_fast_storage.h"
/* Define variables */
#include "set_slow_storage.h"
/* Define functions for initialisation on startup */
#include "set_fast_storage.h"
/* Define functions for real-time processing */
You'll notice multiple inclusions of the same file there, even just in the header. If I mistype something now, the compiler will tell me it can't find the include file "set_fat_storage.h" and I can easily fix it.
So in answer to your question, this is a real, practical example of where multiple inclusion is required.
3
I would say your use case is a motivating example for the_Pragma
directive. The same pragmas can now be expanded from regular macros. So no need to include more than once.
– StoryTeller
Nov 22 at 4:13
@StoryTeller Good point, I could do.
– Graham
Nov 22 at 15:35
add a comment |
up vote
7
down vote
up vote
7
down vote
In the firmware for the product I mainly work on, we need to be able to specify where functions and global/static variables should be allocated in memory. Real-time processing needs to live in L1 memory on chip so the processor can access it directly, fast. Less important processing can go in L2 memory on chip. And anything that doesn't need to be handled particularly promptly can live in the external DDR and go through caching, because it doesn't matter if it's a little slower.
The #pragma to allocate where things go is a long, non-trivial line. It'd be easy to get it wrong. The effect of getting it wrong would be that the code/data would be silently put into default (DDR) memory, and the effect of that might be closed-loop control stopping working for no reason that's easy to see.
So I use include files, which contain just that pragma. My code now looks like this.
Header file...
#ifndef HEADERFILE_H
#define HEADERFILE_H
#include "set_fast_storage.h"
/* Declare variables */
#include "set_slow_storage.h"
/* Declare functions for initialisation on startup */
#include "set_fast_storage.h"
/* Declare functions for real-time processing */
#include "set_storage_default.h"
#endif
And source...
#include "headerfile.h"
#include "set_fast_storage.h"
/* Define variables */
#include "set_slow_storage.h"
/* Define functions for initialisation on startup */
#include "set_fast_storage.h"
/* Define functions for real-time processing */
You'll notice multiple inclusions of the same file there, even just in the header. If I mistype something now, the compiler will tell me it can't find the include file "set_fat_storage.h" and I can easily fix it.
So in answer to your question, this is a real, practical example of where multiple inclusion is required.
In the firmware for the product I mainly work on, we need to be able to specify where functions and global/static variables should be allocated in memory. Real-time processing needs to live in L1 memory on chip so the processor can access it directly, fast. Less important processing can go in L2 memory on chip. And anything that doesn't need to be handled particularly promptly can live in the external DDR and go through caching, because it doesn't matter if it's a little slower.
The #pragma to allocate where things go is a long, non-trivial line. It'd be easy to get it wrong. The effect of getting it wrong would be that the code/data would be silently put into default (DDR) memory, and the effect of that might be closed-loop control stopping working for no reason that's easy to see.
So I use include files, which contain just that pragma. My code now looks like this.
Header file...
#ifndef HEADERFILE_H
#define HEADERFILE_H
#include "set_fast_storage.h"
/* Declare variables */
#include "set_slow_storage.h"
/* Declare functions for initialisation on startup */
#include "set_fast_storage.h"
/* Declare functions for real-time processing */
#include "set_storage_default.h"
#endif
And source...
#include "headerfile.h"
#include "set_fast_storage.h"
/* Define variables */
#include "set_slow_storage.h"
/* Define functions for initialisation on startup */
#include "set_fast_storage.h"
/* Define functions for real-time processing */
You'll notice multiple inclusions of the same file there, even just in the header. If I mistype something now, the compiler will tell me it can't find the include file "set_fat_storage.h" and I can easily fix it.
So in answer to your question, this is a real, practical example of where multiple inclusion is required.
edited Nov 22 at 1:18
answered Nov 22 at 1:12
Graham
1,374414
1,374414
3
I would say your use case is a motivating example for the_Pragma
directive. The same pragmas can now be expanded from regular macros. So no need to include more than once.
– StoryTeller
Nov 22 at 4:13
@StoryTeller Good point, I could do.
– Graham
Nov 22 at 15:35
add a comment |
3
I would say your use case is a motivating example for the_Pragma
directive. The same pragmas can now be expanded from regular macros. So no need to include more than once.
– StoryTeller
Nov 22 at 4:13
@StoryTeller Good point, I could do.
– Graham
Nov 22 at 15:35
3
3
I would say your use case is a motivating example for the
_Pragma
directive. The same pragmas can now be expanded from regular macros. So no need to include more than once.– StoryTeller
Nov 22 at 4:13
I would say your use case is a motivating example for the
_Pragma
directive. The same pragmas can now be expanded from regular macros. So no need to include more than once.– StoryTeller
Nov 22 at 4:13
@StoryTeller Good point, I could do.
– Graham
Nov 22 at 15:35
@StoryTeller Good point, I could do.
– Graham
Nov 22 at 15:35
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53416657%2fwhy-isnt-pragma-once-automatically-assumed%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
23
Is there even any reason to include a single file multiple times? => Could be. A file might have conditional compilation
#ifdefs
in it. So you might say#define MODE_ONE 1
and then#include "has-modes.h"
, and then#undef MODE_ONE
with#define MODE_TWO 1
and#include "has-modes.h"
again. The preprocessor is agnostic about these kinds of things, and maybe sometimes they can make sense.– HostileFork
Nov 21 at 16:40
62
It would make sense as the default. Just not the one they picked when C programmers still rode horses, carried guns and had 16KB of memory
– Hans Passant
Nov 21 at 16:41
11
You can include
<assert.h>
multiple times, with different definitions ofNDEBUG
, in the same source file.– Pete Becker
Nov 21 at 16:45
3
As for
#pragma once
itself, there are hardware environments (typically with networked drives and possible multiple paths to the same header) where it won't work right.– Pete Becker
Nov 21 at 16:48
11
If you have
#pragma once
assumed, what is the way of countermanding that default?#pragma many
? How many compilers have implemented anything like that?– Jonathan Leffler
Nov 21 at 17:20