我正在研究一个已知只能在Windows上运行并在Visual Studio下编译的代码库(它与excel紧密集成,所以它不会去任何地方).我想知道我是否应该使用传统的包含警卫或#pragma once用于我们的代码.我认为让编译器处理#pragma once会产生更快的编译,并且在复制和粘贴时不易出错.它也稍微不那么难看;)
注意:为了获得更快的编译时间,我们可以使用Redundant Include Guards,但这会在包含的文件和包含文件之间增加紧密耦合.通常它没关系,因为防护应该基于文件名,并且只有在你需要改变包含名称时才会改变.
传统上,避免C++中多个头部包含的标准和可移植方法是使用#ifndef - #define - #endif预编译器指令方案,也称为宏保护方案(参见下面的代码片段).
#ifndef MY_HEADER_HPP
#define MY_HEADER_HPP
...
#endif
Run Code Online (Sandbox Code Playgroud)
然而,在大多数实现/编译器中(见下图),有一个更"优雅"的替代方案,其功能与调用的宏保护方案相同#pragma once.#pragma once与宏保护方案相比具有几个优点,包括更少的代码,避免名称冲突,有时提高编译速度.

做了一些研究,我意识到尽管#pragma once几乎所有已知的编译器都支持指令,但是指令是否#pragma once是C++ 11标准的一部分还是存在紊乱.
#pragma once指令是否属于C++ 11标准的一部分吗?#pragma once)的优点/缺点,那也是很好的.我从来没有理解#pragma once什么时候#ifndef #define #endif总是有效的需要.
我已经看到了#pragma comment与其他文件链接的用法,但使用IDE可以更轻松地设置编译器设置.
有哪些其他用法#pragma是有用的,但并不广为人知?
编辑:
我不只是#pragma指令列表之后.也许我应该再多说一下这个问题:
你和你一起写的代码#pragma有用吗?
.
答案一目了然:
感谢所有回答和/或评论的人.以下是我发现有用的一些输入的摘要:
#pragma once或#ifndef #define #endif允许更快地编译大型系统.史蒂夫跳进来支持这一点.#pragma onceMSVC首选,而GCC编译器优化#ifndef #define #endif.因此,应该使用其中之一,而不是两者.#pragma pack了二进制兼容性,而Clifford则反对这一点,因为可移植性和字节序可能存在问题.Evan提供了一个示例代码,Dennis告知大多数编译器会强制执行填充以进行对齐.#pragma warning用来隔离真正的问题,并禁用已经审查过的警告.#pragma comment(lib, header)在不重新设置IDE的情况下轻松移植项目.当然,这不太便携.#pragma message为VC用户提供了一个很好的技巧来输出带有行号信息的消息.詹姆斯更进一步,允许error或warning匹配MSVC的消息,并将适当显示,如错误列表.#pragma region了能够在MSVC中使用自定义消息折叠代码.哇,等等,如果我想发布不使用#pragmas除非必要,该怎么办?
#pragma.荣誉.如果SOers感觉到发布答案的冲动,我会在此列表中添加更多内容.感谢大家!
刚见过这里面 <boost/asio.hpp>
#ifndef BOOST_ASIO_HPP
#define BOOST_ASIO_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
/// ....
#endif // BOOST_ASIO_HPP
Run Code Online (Sandbox Code Playgroud)
无视_MSC_VER预处理器检查,#pragma once在这种情况下有什么好处?在所有情况下以及在所有平台上,预处理器头部保护是否都不能确保头部内容只有included一次?
如果我iostream在文件中包含两次或任何其他头文件会怎样?我知道编译器不会抛出错误.
代码会被添加两次还是内部会发生什么?
当我们包含头文件时实际发生了什么?
标题说明了一切.已#pragma once被标准化了的C++ 0x?我不知道任何编译器没有提供它的实现,几乎总是相同的语义和名称.
我有这样的C++文件
#ifndef _MOVE_H
#define _MOVE_H
class Move {
int x, y;
public:
Move(int initX = 0, int initY = 0) : x(initX), y(initY) {}
int getX() { return x; }
void setX(int newX) { x = newX; }
int getY() { return y; }
void setY(int newY) { y = newY; }
};
#endif
Run Code Online (Sandbox Code Playgroud)
很让我惊讶,所有的代码#ifndef,并#endif简单地由编译器(我发誓,我没有界定忽视_MOVE_H其他地方),我有失踪定义的各种错误.我在想我做错了什么,但是当我尝试使用另一个键时(比如_MOVE_Ha,一切都恢复正常.这是否_MOVE_H意味着C++中的一些特殊内容?
我正在运行Ubuntu 10.04,GCC 4.4.3,如果这很重要的话.
谢谢,
如何通过包含与另一个包含的另一个头文件同名的头文件来创建解决方案?
例如:
// src/blah/a.hpp
#ifndef A_HPP
#define A_HPP
namspace blah
{
class A
{
}
}
#endif
// src/blah/b.hpp
#ifndef B_HPP
#define B_HPP
#includes "a.hpp"
namspace blah
{
class B
{
}
}
#endif
// src/foo/a.hpp
#ifndef A_HPP
#define A_HPP
namspace foo
{
class A
{
}
}
#endif
// src/foo/c.hpp
#ifndef C_HPP
#define C_HPP
#includes "../b.hpp"
#includes "a.hpp" // won't be included due to multiple inclusion prevention
namspace foo
{
class C
{
}
}
#endif
Run Code Online (Sandbox Code Playgroud)
在最后一个头文件中,由于多个包含预处理器保护,因此不会包含a.hpp.真的,这应该没问题,因为类在不同的命名空间中.我意识到,简单的方法是只更改foo/a.hpp的名称或者只是在多重包含守护中给它一个假名.有没有更好的办法?
编辑 我理解你可以通过在#define和#ifndef指令中使用更具描述性的名称来解决这个问题(例如FOO_A_HPP和BLAH_A_HPP),但我想知道这是推荐的还是最好的方法.有些人会建议使用不同的文件名作为更好的解决方案,还是不重要?你会建议使用这个约定: …
现代C和C++编译器支持非标准的#pragma once预处理器指令,它与经典的头部保护器具有类似的用途:
#ifndef hopefully_unique_identifier_that_doesnt_hurt_the_code
#define hopefully_unique_identifier_that_doesnt_hurt_the_code
// some code here
#endif
Run Code Online (Sandbox Code Playgroud)
一个问题,我知道,使用经典的方法是,一旦你包含一个标题,你必须#undef使用标题保护宏再次包含它(这样做,对我来说,是一个主要的代码气味,但那是除此之外).该方法也出现了同样的问题#pragma once,但没有允许多次包含标题的可能性.
经典方法的另一个问题是,您可能会意外地在不相关的位置定义相同的宏,因此要么不包括预期的标题,要么做一些其他令人讨厌的东西,这是我无法想象的.这在实践中相当容易避免,通过遵守某些约定,例如将宏基于类似UUID的对象(即随机字符串)或(不太理想的方法),基于文件的名称,它们在.
在现实生活中,我很少遇到任何这些潜在问题,所以我并不认为它们是主要问题.
我能想到的唯一潜在的现实生活问题#pragma once是,它不是一个标准的东西 - 你依赖的东西可能无处不在,即使它存在,在实践中,无处不在(*).
那么,#pragma once除了我已经提到过的问题之外,还有哪些潜在的问题?我是否过于相信在实践中,无处不在?
(*)只有少数人使用的一些次要编译器,被排除在外.
我的所有头文件都使用包括警卫和pragma一次:
#pragma once
#ifndef FILE_NAME_H
#define FILE_NAME_H
class foo
{
//foo interface..
};
#endif /* FILE_NAME_H */
Run Code Online (Sandbox Code Playgroud)
我知道pragma曾经不是标准的,并且可能在编译器中不一样,但它是否有可能导致错误?以某种方式测试它是否可用,是否会更好?
#ifdef THIS_COMPILER_SUPPORTS_PRAGMA_ONCE
#pragma once
#endif
#ifndef FILE_NAME_H
#define FILE_NAME_H
class foo
{
//foo interface..
};
#endif /* FILE_NAME_H */
Run Code Online (Sandbox Code Playgroud)
我想提供一次pragma作为可能加速编译和避免名称冲突的选项,同时仍然提供编译器之间的兼容性.