Include Guards: #ifndef vs #pragma once


Include Guards: #ifndef vs #pragma once

The majority of my compiler experience is with Microsoft’s Visual Studio, and as such I’ve always wondered about why you would bother with the #ifndef include guards. After all Visual Studio already stubs out new classes for you with the #pragma once pre-processor directive. A quick Google will tell you that they essentially do the same thing so why would you want to go with the uglier #ifndef guards?

Well let’s look at what both of these pre-processor directives actually do first.

#ifndef

This is the ‘classic’ include guard that you will probably see most often. The idea is that it first checks to see whether the file has already been included in the current compilation unit. If it has it does not include it again, if not then it will include it. It does this my checking to see whether the guard symbol has already been defined or not. The first time it includes the file it defines the symbol then. It’s as simple as that. A common implementation might be:

#ifndef HEADER_H
#define HEADER_H

// Header file

#endif	// #ifndef HEADER_H

By doing this we can guarantee that a header file will never be included more than once. The only minor problem with this approach is that the file is still opened each time the compiler wants to include it, to check whether or not it has already been included. If it has already been included then we don’t really want to have to open the file again as it will only increase our compile time.

#pragma once

#pragma once seems to solve the problem of the traditional include guards, whilst also being clearer and cleaner. The directive prevents the pre-processor from ever including or opening the same header file more than once in the same compilation unit. A typical implementation would be:

#pragma once

// Header file

This code looks so much better and is far more readable. Plus it’s actually better than the previous approach right?

Well yes and no. The big problem with #pragma once is that it is a non-standard directive which means that it is not supported by every compiler. This means that if you want to keep the efficiency of #pragma once where it is supported but still guarantee that the include guards will work properly on every compiler, you have to combine the previous two approaches which results in some ugly code like the following:

#ifndef HEADER_H
#define HEADER_H

#if _MSC_VER > 1000
#pragma once
#endif	// #if _MSC_VER > 1000

// Header file

#endif	// #ifndef HEADER_H

This is definitely less readable than either of the previous approaches but if we can keep that efficiency then it’s worth it surely. The thing is that most of the compilers that know how to use #pragma once are also smart enough to only open header files with the include guards once anyway.

So the bottom line is that if you think your code may need to work cross-platform use the traditional include guards. If, however, you are absolutely sure that you’re only going to be using the one platform and your compiler supports #pragma once then go ahead and use that.

Personally until (or if) #pragma once becomes the standard I shall stick with the traditional include guards. It gives me the flexibility to reuse my code on various projects knowing that it will run correctly and efficiently without having to refactor my code depending on the platform I am working on.


转载自:http://tjclifton.com/2012/06/04/include-guards-ifndef-vs-pragma-once/


补充:log4cplus项目里经常把这两种放在一起使用,比如loglevel.h中

#ifndef LOG4CPLUS_LOGLEVEL_HEADER_
#define LOG4CPLUS_LOGLEVEL_HEADER_

#include <log4cplus/config.hxx>

#if defined (LOG4CPLUS_HAVE_PRAGMA_ONCE)
#pragma once
#endif

// ...

#endif // LOG4CPLUS_LOGLEVEL_HEADER_

貌似是想取这两者的优点,但同样也可能不足都引入了:宏名冲突 或者 不支持#pragma once的编译器报错。

但目前看来,支持#prama once的编译器越来越多。

至于选用哪个,是否混用,见仁见智,只要项目内统一就好。google的styleguide好像只提到了include guard。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值