`

#pragma once 与 #ifndef 解析

 
阅读更多

    为了避免同一个文件被include多次,C/C++中有两种方式,一种是#ifndef方式,一种是#pragma once方式。在能够支持这两种方式的编译器上,二者并没有太大的区别,但是两者仍然还是有一些细微的区别。
    方式一:

    #ifndef __SOMEFILE_H__
    #define __SOMEFILE_H__
    ... ... // 声明、定义语句
    #endif


    方式二:

    #pragma once
    ... ... // 声明、定义语句

    #ifndef的方式受C/C++语言标准支持。它不光可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件(或者代码片段)不会被不小心同时包含。
    当然,缺点就是如果不同头文件中的宏名不小心“撞车”,可能就会导致你看到头文件明明存在,编译器却硬说找不到声明的状况——这种情况有时非常让人抓狂。
    由于编译器每次都需要打开头文件才能判定是否有重复定义,因此在编译大型项目时,ifndef会使得编译时间相对较长,因此一些编译器逐渐开始支持#pragma once的方式。

 

    #pragma once一般由编译器提供保证:同一个文件不会被包含多次。注意这里所说的“同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。你无法对一个头文件中的一段代码作pragma once声明,而只能针对文件。
    其好处是,你不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题。大型项目的编译速度也因此提高了一些。
    对应的缺点就是如果某个头文件有多份拷贝,本方法不能保证他们不被重复包含。当然,相比宏名碰撞引发的“找不到声明”的问题,这种重复包含很容易被发现并修正。

 

    #pragma once方式产生于#ifndef之后,因此很多人可能甚至没有听说过。目前看来#ifndef更受到推崇。因为#ifndef受C/C++语言标准的支 持,不受编译器的任何限制;而#pragma once方式却不受一些较老版本的编译器支持,一些支持了的编译器又打算去掉它,所以它的兼容性可能不够好。一般而言,当程序员听到这样的话,都会选 择#ifndef方式,为了努力使得自己的代码“存活”时间更久,通常宁愿降低一些编译性能,这是程序员的个性,当然这是题外话啦。

 

    还看到一种用法是把两者放在一起的:

    #pragma once
    #ifndef __SOMEFILE_H__
    #define __SOMEFILE_H__
    ... ... // 声明、定义语句
    #endif

    看起来似乎是想兼有两者的优点。不过只要使用了#ifndef就会有宏名冲突的危险,也无法避免不支持#pragma once的编译器报错,所以混用两种方法似乎不能带来更多的好处,倒是会让一些不熟悉的人感到困惑。

 

    选择哪种方式,应该在了解两种方式的情况下,视具体情况而定。只要有一个合理的约定来避开缺点,我认为哪种方式都是可以接受的。而这个已经不是标准或者编译器的责任了,应当由程序员自己或者小范围内的开发规范来搞定。

    btw:我看到GNU的一些讨论似乎是打算在GCC 3.4(及其以后?)的版本取消对#pragma once的支持。不过事实上,我手上的GCC 3.4.2和GCC 4.1.1仍然支持#pragma once,甚至没有deprecation warning,倒是GCC2.95会对#pragma once提出warning。
    VC6及其以后版本亦提供对#pragma once方式的支持,这一特性应该基本稳定下来了。

分享到:
评论

相关推荐

    #pragma_命令集合.pdf

    ### #pragma 命令集合解析 在编程领域中,`#pragma` 是一个非常有用的预处理器指令,它允许程序员直接向编译器传递特定的信息或控制编译过程中的某些特性。下面,我们将深入探讨几个常见的 `#pragma` 指令,并详细...

    C头文件避免重复包含问题

    值得注意的是,虽然`#pragma once`在多数情况下能有效防止头文件重复包含,但`#ifndef`...`#endif`(include guard)方法更具有移植性,因为它适用于所有遵循C/C++标准的编译器。 在实际项目中,我们还可以采用其他...

    yuv源码解读 (2).docx

    当同一个头文件在多个地方被包含时,`#pragma once`确保头文件的内容只被处理一次,避免了重复定义的问题,类似于`#ifndef`和`#define`的宏定义方式,但更简洁且跨编译器支持较好。 总的来说,这些预处理技术在软件...

    C++常见编译/链接错误及其解决办法

    #pragma once 与 #ifndef 的区别 **错误描述**:这两个指令都是为了防止头文件被重复包含,但它们之间存在细微差别。 **#ifndef 方式**: ```cpp #ifndef __SOMEFILE_H__ #define __SOMEFILE_H__ // 一些声明...

    yuv源码解读.docx

    《YUV源码解读——深入理解预编译与C++编程实践》 在计算机编程,尤其是C++领域,预编译是提高编译效率的关键技术之一。本文将围绕“YUV源码解读.docx”文档中的内容,深入解析预编译头文件(如`stdafx.h`)以及...

    C++的头文件互相包含的问题

    ### C++头文件互相包含问题解析与解决方案 在C++编程中,头文件(.h 或 .hpp)的管理是构建复杂项目时的关键部分。当两个或多个类相互依赖,即一个类的定义中需要另一个类的信息时,就会出现头文件互相包含的问题,...

    C语言18个经典问题答录

    ### C语言18个经典问题解析 #### 1. malloc函数初始化指针 在C语言中,`malloc()`函数用于动态分配内存空间。例如:`char *p = malloc(10);` 这行代码为指针`p`分配了10个字节的空间。需要注意的是,`malloc()`...

    Dev-cpp API

    #pragma once ``` - **`#undef`**:取消宏定义。 ```cpp #undef TRUE ``` #### 三、预定义变量 预定义变量由编译器自动定义,无需显式声明。 - **`__LINE__`**:表示当前行号。 - **`__FILE__`**:表示...

    c语言经典问题答录

    `#pragma once`是一种常用的预处理器指令,用于防止头文件在编译过程中被多次包含,从而避免重复定义错误。虽然不是所有编译器都支持这一指令,但在许多现代编译器中,它是一个方便且有效的解决方案,可以替代传统的...

    yuv源码解读.pdf

    `#pragma once`预编译指令确保头文件只被编译一次,避免了重复包含导致的编译错误。在`stdafx.h`中,我们通常看到包含如`<afxwin.h>`、`<afxext.h>`、`<afxdtctl.h>`等MFC(Microsoft Foundation Classes)库的...

    c++ 头文件详解

    4. **空头文件**:有时为了确保某些声明只被包含一次,我们会创建一个空头文件(如`stdafx.h`),并在其中使用`#pragma once`或`#ifndef...#define...#endif`来防止重复包含。 使用头文件的注意事项: 1. **包含...

    A fast preprocessor for C and C++.zip

    3. **头文件管理**:C和C++程序经常包含多个头文件,快速的预处理器可能有高效的包含文件处理策略,比如防止重复包含(`#pragma once`或`#ifndef` guards)和最小化头文件的读取次数。 4. **性能优化**:预处理器的...

    C语言学习笔记

    2. **`#pragma once`**: ```c #pragma once // 文件内容 ``` 这个预处理器指令在某些编译器(如Microsoft Visual Studio)中支持,它能够确保头文件只被包含一次。相比于`#ifndef`/`#define`/`#endif`结构,...

    程序员面试宝典题目总结

    7. 头文件#ifndef/define/endif和#pragma once的作用:防止头文件被重复包含。ifndef/define/endif是标准的条件编译方法,而#pragma once是编译器特定的指令,用于相同效果,但不是标准C/C++的一部分。 8. sizeof...

    笔试题及答案(富士施乐)

    2. **`#pragma once`**:这是一个非标准但广泛支持的预处理器指令,它告诉编译器如果这个文件已经被包含过一次,则忽略后续的包含请求。 #### 题目三:C++中`new/delete`与`malloc/free`的区别 `new/delete`和`...

    c++学习笔记

    - **`#pragma once`**: - 功能: 确保文件只被编译一次,通常用于头文件中,防止重复包含。 - 替代方案: 使用`#ifndef`, `#define`, 和`#endif`来实现相同的功能。 - 示例: ```cpp #ifndef HEADER_H_ #define ...

    LNK2005错误

    - 使用预处理指令(如 `#ifndef MY_H_FILE`, `#define MY_H_FILE` 或 `#pragma once`)来确保一个头文件不会被多次包含,这可以防止因重复定义而引发的 LNK2005 错误。 ```cpp // header.h #ifndef MY_H_FILE ...

    读写Avi文件的vc程序

    `stdafx.cpp`和`stdafx.h`中的`#pragma once`或`#ifndef/#define/#endif`结构用于防止头文件被多次包含,确保编译的正确性。 在实际的编程过程中,读取AVI文件涉及解析其文件结构,包括索引块(index chunk)、流...

Global site tag (gtag.js) - Google Analytics