《The _Pragma("once") vs include guards》
我写的issue原文:
标题:Consider changing include guards to pragma once.
We can use the _Pragma directive for header file guard.
example:
#ifndef FOO_BAR_BAZ_H_#define FOO_BAR_BAZ_H_...#endif // FOO_BAR_BAZ_H_change to
_Pragma("once")There are several factors to support the lowcase file/directory name.
portability
Cross-platform problems will not occur, compiler implement standard, they will support it.
readability
Generally, if you just want to do some guard, you should not care about the name and the directory of this file. and the naming of the guard is yet another big question, nonstandard things always end up in a fight.
convenience
just copy & paste for the _Pragma(“once”), here and there.
Computer industry set the standards, so does our company.
feel free to refer to
tencent cplusplus code standard, “2.2.【必需】 头文件保护”:
https://git.code.oa.com/standards/cpp#22%E5%BF%85%E9%A1%BB-%E5%A4%B4%E6%96%87%E4%BB%B6%E4%BF%9D%E6%8A%A4
image.png
More importantly, the _Pragma directive is the standard level in C++, instead of the a specific compiler extension like GCC’s # pragma, which maximizes stability and compatibility.
see:
我写的wiki原文(工程标准 -> C++ Coding Guideline):
标题:The _Pragma(“once”) Guard
_Pragma操作符
在C/C++标准中,#pragma是一条预解决的指令(preprocessor directive)。简单地说,#pragma是用来向编译器传达语言标准以外的少量信息。举个简单的例子,假如我们在代码的头文件中定义了以下语句:
#pragma once要达到与上例#pragma相似的效果,则只要要如下代码就可。
_Pragma("once");而相比预解决指令#pragma,因为_Pragma是一个操作符,因而可以嵌套在宏中。我们可以看看下面这个例子:
#define CONCAT(x) PRAGMA(concat on #x)#define PRAGMA(x) _Pragma(#x)CONCAT( ..\concat.dir )这里,CONCAT( ..concat.dir )最终会产生_Pragma(concat on “..concat.dir”)这样的效果。而#pragma则不能在宏中开展,因而从灵活性上来讲,标准的 _Pragma具备更大的灵活性。
注意,为什么强调“标准”,我指的是
_Pragma("once")而不是
#pragma once以上,可以看出,不论从可移植性、可读性、便利性,还是规范角度看,_Pragma(“once”)都有优势。使用新标准可以提高开发效率,用最自然的思维方式、最简单的代码,表达大量内容。
由于前者是语言层面的标准,然后者是编译器的扩展,可能在标准通过_Pragma操作符之前,GCC就已经实现了#pragma,这个时候,windows,macOS系统的编译器可能是不认识#pragma的,他可能是别的foo, bar。但是,标准通过之后,所有编译器都将遵循标准。
所以,使用标准,会是最通用的方式,也是我们的方式。
详见n3690.pdf:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf
image.png
不过有观点认为,我们不该使用_Pragma(“once”),由于编译器的实现有bug。(https://stackoverflow.com/questions/1143936/pragma-once-vs-include-guards)
我们确立一个标准,提高开发效率的同时,也要确认该标准能否稳固可用,为了防止引入未知的问题。
网上的资料不多,就直接看了下内核、编译器的实现。
早期存在的问题在于,比方foo.h -> /path/to/foo.h链接会共享相同的inode,导致编译器无法区分。(详见附录“内核实现分析”)
在问题相关的上下游,有如下若干事实:
编译器层面,gcc在3.4.0版本的时候已经修复了上述问题。(详见附录“编译器实现分析”)
开发者层面,绝大多数项目都不会存在上述问题。
这让我们相信标准,且相信标准的实现。
极端假设,即便编译器仍存在这个所谓的bug,并且我们刻意触发了,那么会不会有严重问题呢?答案能否定的。由于,它和ifndef造成的macro冲突问题是同一级别的,而且更容易在最早期的编译阶段被发现。换言之,既然你都可以接受ifndef,那么为什么不能接受_Pragma(“once”)呢,后者即使是在最邪恶的情况下,也不会比前者错得更多。
结论:我们可以使用标准的_Pragma操作符。
大家已经将这个结论,作为我们的共识。在代码规范中已升级。
具体的编码,可以直接遵循规范:
假如存在ifndef头文件保护,那么麻烦进行如下替换:
将
#ifndef FOO_BAR_BAZ_H_#define FOO_BAR_BAZ_H_...#endif // FOO_BAR_BAZ_H_改成
_Pragma("once")假如不存在,请直接使用
_Pragma("once")附
内核实现分析(linux-5.7.0):
image.png
编译器实现分析(gcc-9.2.0):
image.png
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 《The _Pragma("once") vs include guards》