Why isn't #pragma once automatically assumed?











up vote
48
down vote

favorite
11












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?










share|improve this question




















  • 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 of NDEBUG, 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















up vote
48
down vote

favorite
11












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?










share|improve this question




















  • 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 of NDEBUG, 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













up vote
48
down vote

favorite
11









up vote
48
down vote

favorite
11






11





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?










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 of NDEBUG, 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




    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 of NDEBUG, 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












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 #includeing 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. #pragmas 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.







share|improve this answer























  • And another take on why not standardize once
    – user4581301
    Nov 21 at 19:05






  • 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








  • 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


















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 (#defines). 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.






share|improve this answer























  • 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 #defines 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


















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.






share|improve this answer























  • 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




















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.






share|improve this answer

















  • 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


















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.






share|improve this answer

















  • 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 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


















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.






share|improve this answer



















  • 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











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















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

























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 #includeing 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. #pragmas 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.







share|improve this answer























  • And another take on why not standardize once
    – user4581301
    Nov 21 at 19:05






  • 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








  • 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















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 #includeing 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. #pragmas 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.







share|improve this answer























  • And another take on why not standardize once
    – user4581301
    Nov 21 at 19:05






  • 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








  • 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













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 #includeing 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. #pragmas 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.







share|improve this answer














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 #includeing 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. #pragmas 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.








share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 21 at 17:46

























answered Nov 21 at 17:41









Max Langhof

7,4781233




7,4781233












  • And another take on why not standardize once
    – user4581301
    Nov 21 at 19:05






  • 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








  • 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






  • 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








  • 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












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 (#defines). 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.






share|improve this answer























  • 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 #defines 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















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 (#defines). 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.






share|improve this answer























  • 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 #defines 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













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 (#defines). 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.






share|improve this answer














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 (#defines). 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.







share|improve this answer














share|improve this answer



share|improve this answer








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 #defines 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






  • 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 #defines 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 #defines 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 #defines 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










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.






share|improve this answer























  • 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

















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.






share|improve this answer























  • 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















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.






share|improve this answer














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.







share|improve this answer














share|improve this answer



share|improve this answer








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




















  • 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












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.






share|improve this answer

















  • 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















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.






share|improve this answer

















  • 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













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.






share|improve this answer












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.







share|improve this answer












share|improve this answer



share|improve this answer










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














  • 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










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.






share|improve this answer

















  • 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 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















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.






share|improve this answer

















  • 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 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













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.






share|improve this answer












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.







share|improve this answer












share|improve this answer



share|improve this answer










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 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














  • 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 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








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










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.






share|improve this answer



















  • 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















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.






share|improve this answer



















  • 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













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.






share|improve this answer














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.







share|improve this answer














share|improve this answer



share|improve this answer








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














  • 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


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














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





















































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







Popular posts from this blog

Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

ComboBox Display Member on multiple fields

Is it possible to collect Nectar points via Trainline?