我已经读过使用时会有一些编译器优化,#pragma once这会导致更快的编译.我认为这是非标准的,因此可能造成跨平台兼容性问题.
这是非Windows平台(gcc)上大多数现代编译器支持的东西吗?
我想避免平台编译问题,但也想避免后备警卫的额外工作:
#pragma once
#ifndef HEADER_H
#define HEADER_H
...
#endif // HEADER_H
Run Code Online (Sandbox Code Playgroud)
我应该担心吗?我是否应该在这方面进一步消耗精力?
任何人都可以通过一个简单的例子从头到尾解释如何在C中创建头文件.
我有一个php文件,我将作为一个包含专门使用.因此,当我通过输入URL而不是包含它来直接访问它时,我想抛出一个错误而不是执行它.
基本上我需要在php文件中进行如下检查:
if ( $REQUEST_URL == $URL_OF_CURRENT_PAGE ) die ("Direct access not premitted");
Run Code Online (Sandbox Code Playgroud)
是否有捷径可寻?
关于包括警卫的两个常见问题:
第一个问题:
为什么不包括保护我的头文件不受相互的,递归包含的警卫?我不断收到有关不存在的符号的错误,这些符号显然存在,甚至每次我写下类似的东西时都会出现更奇怪的语法错误:
"啊"
#ifndef A_H
#define A_H
#include "b.h"
...
#endif // A_H
Run Code Online (Sandbox Code Playgroud)
"BH"
#ifndef B_H
#define B_H
#include "a.h"
...
#endif // B_H
Run Code Online (Sandbox Code Playgroud)
"的main.cpp"
#include "a.h"
int main()
{
...
}
Run Code Online (Sandbox Code Playgroud)
为什么我会收到编译"main.cpp"的错误?我需要做些什么来解决我的问题?
第二个问题:
为什么不包括防止多个定义的警卫?例如,当我的项目包含两个包含相同标题的文件时,链接器有时会抱怨多次定义某个符号.例如:
"header.h"
#ifndef HEADER_H
#define HEADER_H
int f()
{
return 0;
}
#endif // HEADER_H
Run Code Online (Sandbox Code Playgroud)
"source1.cpp"
#include "header.h"
...
Run Code Online (Sandbox Code Playgroud)
"source2.cpp"
#include "header.h"
...
Run Code Online (Sandbox Code Playgroud)
为什么会这样?我需要做些什么来解决我的问题?
我目前正在开展一个大型项目并且维护所有这些包括警卫让我疯狂!手工编写是令人沮丧的浪费时间.虽然许多编辑可以生成包含警卫,但这并没有多大帮助:
编辑器根据文件名生成保护符号.如果在不同目录中具有相同文件名的标头,则会出现此问题.他们两个都会得到相同的包括后卫.将目录结构包含在保护符号中需要编辑器的一些奇特的方法,因为宏中的斜杠和反斜杠不是最好的.
当我必须重命名文件时,我应该重命名所有包含警戒(在ifndef中,定义和理想的endif的注释).烦人.
预处理器充斥着大量的符号,而不知道它们的含义.
然而,定义包含一次,编译器每次遇到标题包含时仍会打开标题.
包含防护不适合命名空间或模板.实际上他们正在颠覆命名空间!
你的守卫符号有可能不是唯一的.
当程序在单个目录中包含少于1000个标头时,它们可能是可接受的解决方案.但是现在呢?它很古老,与现代编码习惯无关.令我困扰的是,这个问题几乎可以通过#pragma once指令完全解决.为什么不是标准?
我已经看到 #ifndef ABC并#if !defined (ABC)在同一个C源文件中.
他们之间有细微的差别吗?(如果是风格问题,为什么有人会在同一个文件中使用它们)
解决了
真正帮助我的是,我可以在.cpp文件中#include标头而不会导致重新定义的错误.
我是C++的新手,但我在C#和Java方面有一些编程经验,所以我可能会遗漏一些C++独有的基础知识.
问题是我真的不知道什么是错的,我会粘贴一些代码来试图解释这个问题.
我有三个类,GameEvents,Physics和GameObject.我有每个标题.GameEvents有一个Physics和一个GameObjects列表.Physics有一个GameObjects列表.
我想要实现的是我希望GameObject能够访问或拥有一个Physics对象.
如果我只是在GameObject中#include"Physics.h",我会得到"错误C2111:'ClassXXX':'class'类型redtifinition",我理解.这就是我认为#include-guard有帮助的地方所以我在我的Physics.h中添加了一个包含守卫,因为那是我想要包含两次的标题.
这是它的外观
#ifndef PHYSICS_H
#define PHYSICS_H
#include "GameObject.h"
#include <list>
class Physics
{
private:
double gravity;
list<GameObject*> objects;
list<GameObject*>::iterator i;
public:
Physics(void);
void ApplyPhysics(GameObject*);
void UpdatePhysics(int);
bool RectangleIntersect(SDL_Rect, SDL_Rect);
Vector2X CheckCollisions(Vector2X, GameObject*);
};
#endif // PHYSICS_H
Run Code Online (Sandbox Code Playgroud)
但如果我在GameObject.h中#include"Physics.h",现在就像这样:
#include "Texture2D.h"
#include "Vector2X.h"
#include <SDL.h>
#include "Physics.h"
class GameObject
{
private:
SDL_Rect collisionBox;
public:
Texture2D texture;
Vector2X position;
double gravityForce;
int weight;
bool isOnGround;
GameObject(void);
GameObject(Texture2D, Vector2X, int);
void UpdateObject(int);
void Draw(SDL_Surface*);
void SetPosition(Vector2X);
SDL_Rect GetCollisionBox(); …Run Code Online (Sandbox Code Playgroud) 
http://en.wikipedia.org/wiki/Pragma_once
当所有这些编译器都支持时,我还应该使用包含保护#pragma once吗?
很多关于堆栈溢出的响应都表示要使用它们兼容,但我不确定它是否仍然是真的.今天哪些编译器不支持#pragma once?
我不确定在它成为widley之前使用两者是否只是一个推荐,或者是否仍然有很好的理由使用这两种方法.
什么时候只使用#pragma once会导致问题的例子?
在LearnCpp.com上| 1.10 - 首先看一下预处理器.在Header guards下,有一些代码片段:
add.h:
#include "mymath.h"
int add(int x, int y);
Run Code Online (Sandbox Code Playgroud)
subtract.h:
#include "mymath.h"
int subtract(int x, int y);
Run Code Online (Sandbox Code Playgroud)
main.cpp中:
#include "add.h"
#include "subtract.h"
Run Code Online (Sandbox Code Playgroud)
在实施头部防护时,提到如下:
#ifndef ADD_H
#define ADD_H
// your declarations here
#endif
Run Code Online (Sandbox Code Playgroud)
int main()来#endif吗?_H约定还是必须做的事情?谢谢.
我对C和编译过程的基本知识最近变得生疏.我试图找出以下问题的答案,但我无法连接编译,链接和预处理阶段基础知识.快速搜索谷歌也没什么帮助.所以,我决定来到最终的知识来源:)
我知道:不应该在.h文件中定义变量.可以在那里宣布它们.
原因:因为头文件可能包含在多个位置,因此重新定义变量多次(链接器给出错误).
可能的解决方法:在头文件中使用header-guard并在其中定义变量.
它真的是一个解决方案:不.因为标题保护是用于预处理阶段.那就是告诉编译器这部分已经包含在内并且不再包含它.但是我们的多重定义错误来自链接器部分 - 在编译之后很久.
整件事让我对预处理和链接的工作方式感到困惑.如果已经定义了头部保护符号,我认为预处理将不包括代码.在那种情况下,不应该解决变量问题的多重定义吗?
这些预处理指令会在标题保护下重新定义编码过程,但是链接器仍会获得符号的多个定义,会发生什么?