告诉编译器只包含一次文件有什么意义?默认情况下它不会有意义吗?是否有任何理由多次包含单个文件?为什么不假设呢?是与特定硬件有关吗?
Max*_*hof 80
这里有多个相关问题:
为什么#pragma once不自动执行?
因为在某些情况下您希望多次包含文件.
为什么要多次包含文件?
其他答案(Boost.Preprocessor,X-Macros,包括数据文件)中给出了几个原因.我想添加一个"避免代码重复"的特定示例:OpenFOAM鼓励一种风格,其中#include功能中的点点滴滴是一个常见的概念.例如,参见本讨论.
好的,但是为什么它不是选择退出的默认值?
因为它实际上并未由标准指定.#pragma根据定义,特定于实现的扩展.
为什么还#pragma once没有成为一个标准化的功能(因为它得到广泛支持)?
因为以平台无关的方式固定"同一个文件"实际上是非常困难的.有关更多信息,请参阅此答案.
Jes*_*uhl 36
您可以在文件中的#include 任何位置使用,而不仅仅是在全局范围内 - 例如,在函数内部(如果需要,可以多次使用).当然,丑陋和不好的风格,但可能和偶尔明智(取决于你包括的文件).如果#include只是一次性事情那么那就行不通了.#include毕竟,只是做了愚蠢的文本替换(cut'n'paste),并不是你所包含的所有内容都必须是头文件.例如,您可能#include包含一个包含自动生成数据的文件,其中包含用于初始化a的原始数据std::vector.喜欢
std::vector<int> data = {
#include "my_generated_data.txt"
}
Run Code Online (Sandbox Code Playgroud)
并且"my_generated_data.txt"是编译期间构建系统生成的内容.
或者也许我懒惰/愚蠢/愚蠢并把它放在一个文件中(非常人为的例子):
const noexcept;
Run Code Online (Sandbox Code Playgroud)
然后我做
class foo {
void f1()
#include "stupid.file"
int f2(int)
#include "stupid.file"
};
Run Code Online (Sandbox Code Playgroud)
另一个稍微不那么做作的例子是一个源文件,其中许多函数需要在命名空间中使用大量类型,但是你不想只是说using namespace foo;全局,因为这会用很多其他东西来调用全局命名空间你不想要.所以你创建一个包含的文件"foo"
using std::vector;
using std::array;
using std::rotate;
... You get the idea ...
Run Code Online (Sandbox Code Playgroud)
然后在源文件中执行此操作
void f1() {
#include "foo" // needs "stuff"
}
void f2() {
// Doesn't need "stuff"
}
void f3() {
#include "foo" // also needs "stuff"
}
Run Code Online (Sandbox Code Playgroud)
注意:我不是在提倡做这样的事情.但是有可能在一些代码库中完成,我不明白为什么不应该允许它.它确实有它的用途.
也可能是您包含的文件的行为有所不同,具体取决于某些宏的值#define.因此,您可能希望在首次更改某个值后将文件包含在多个位置,以便在源文件的不同部分中获得不同的行为.
PSk*_*cik 26
包括多次可用,例如,使用X-macro技术:
data.inc:
X(ONE)
X(TWO)
X(THREE)
Run Code Online (Sandbox Code Playgroud)
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
};
Run Code Online (Sandbox Code Playgroud)
我不知道任何其他用途.
T.E*_*.D. 19
您似乎在假设即使语言中存在的"#include"功能的目的是为了将程序分解为多个编译单元提供支持的情况下运行.那是不对的.
它可以执行该角色,但这不是其预期目的.C 最初是为比重新实现Unix的PDP-11 Macro-11 Assembly 开发的稍高级语言.它有一个宏预处理器,因为这是Macro-11的一个功能.它能够以文本方式包含来自另一个文件的宏,因为这是Macro-11的一个特性,它们正在移植到新的C编译器的现有Unix已经使用了.
现在事实证明"#include" 对于将代码分成编译单元很有用,因为(可以说)有点像黑客.然而,这个黑客存在意味着它成为了在C.做到这一点的方式存在意味着没有新的方法不断的事实的方式,其实需要要创建提供此功能,所以没有什么更安全(如:不容易受到多-inclusion)曾经创造过.因为它已经在C中,所以它被复制到C++以及C语言和惯用语的其余部分.
有一个建议为C++提供一个合适的模块系统,这样这个45岁的预处理器黑客最终可以免除.我不知道这是多么迫近.我已经听说它已经有十多年了.
Ser*_*eyA 10
不,这将显着阻碍例如图书馆作者可用的选项.例如,Boost.Preprocessor允许使用预处理器循环,实现这些循环的唯一方法是通过同一文件的多个包含.
Boost.Preprocessor是许多非常有用的库的构建块.
在我主要使用的产品的固件中,我们需要能够指定应在内存中分配函数和全局/静态变量的位置.实时处理需要存储在芯片上的L1存储器中,以便处理器可以直接,快速地访问它.不太重要的处理可以在芯片上的L2存储器中进行.任何不需要特别及时处理的东西都可以存在于外部DDR中并通过缓存,因为如果速度稍慢则没关系.
分配到哪里的#pragma是一条很长的,非平凡的线.这很容易弄错.犯错的效果将是代码/数据将被悄悄放进默认(DDR)内存,并且效果是可能的闭环控制停止无缘无故,很容易看到工作.
所以我使用include文件,其中只包含该pragma.我的代码现在看起来像这样.
头文件......
#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
Run Code Online (Sandbox Code Playgroud)
来源......
#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 */
Run Code Online (Sandbox Code Playgroud)
你会注意到同一个文件的多个包含,即使只是在标题中.如果我现在输入错误,编译器会告诉我它找不到包含文件"set_fat_storage.h",我可以轻松修复它.
因此,在回答您的问题时,这是一个真实,实用的例子,说明需要多个包含.
| 归档时间: |
|
| 查看次数: |
6039 次 |
| 最近记录: |