精华内容
下载资源
问答
  • 预处理/预编译

    千次阅读 2017-11-04 21:07:54
    一、预处理的由来  在C++的历史发展中,有很多的语言特征(特别是语言的晦涩之处)来自于C语言,预处理就是其中的一... 处理器的主要作用就是把通过预处理的内建功能对一个资源进行等价替换,最常见的预处理有:文
    一、预处理的由来
        在C++的历史发展中,有很多的语言特征(特别是语言的晦涩之处)来自于C语言,预处理就是其中的一个。C++从C语言那里把C语言预处理器(被Bjarne博士简称为Cpp,不知道是不是C Program Preprocessor的简称)继承过来。

    二、常见的预处理功能

        预处理器的主要作用就是把通过预处理的内建功能对一个资源进行等价替换,最常见的预处理有:文件包含,条件编译、布局控制和宏替换4种。

        (1)文件包含

        #include 是一种最为常见的预处理,主要是做为文件的引用组合源程序正文。
        (2)条件编译
        #if,#ifndef,#ifdef,#endif,#undef等也是比较常见的预处理,主要是进行编译时进行有选择的挑选,注释掉一些指定的代码,以达到版本控制、防止对文件重复包含的功能。
        (3)布局控制
        #progma,这也是我们应用预处理的一个重要方面,主要功能是为编译程序提供非常规的控制流信息
        (4)宏替换

        #define,这是最常见的用法,它可以定义符号常量、函数功能、重新命名、字符串的拼接等各种功能。


    三、预处理指令
        预处理指令的格式如下:
        #directive tokens
    #符号应该是这一行的第一个非空字符,一般我们把它放在起始位置。如果指令一行放不下,可以通过进行控制,例如:
        #define Error if(error) exit(1)
    等价于:
        #define Error
        if(error) exit(1)
    不过我们为了美化起见,一般都不怎么这么用,更常见的方式如下:

    # ifdef __BORLANDC__
    if_true<(is_convertible<Value,named_template_param_base>::value)>::
    template then<make_named_arg, make_key_value>::type Make;
    # else
    enum { is_named = is_named_parameter<Value>::value };
    typedef typename if_true<(is_named)>::template
    then<make_named_arg, make_key_value>::type Make;
    # endif
        下面我们看一下常见的预处理指令:

    #define 宏定义
    #undef 未定义宏
    #include 文本包含
    #ifdef 如果宏被定义就进行编译
    #ifndef 如果宏未被定义就进行编译
    #endif 结束编译块的控制
    #if 表达式非零就对代码进行编译
    #else 作为其他预处理的剩余选项进行编译
    #elif 这是一种#else和#if的组合选项
    #line 改变当前的行数和文件名称
    #error 输出一个错误信息
    #pragma 为编译程序提供非常规的控制流信息
        下面我们对这些预处理进行一一的说明,考虑到宏的重要性和繁琐性,我们把它放到最后讲。


    四、文件包含指令: #include
        这种预处理使用方式是最为常见的,平时我们编写程序都会用到,最常见的用法是:

    #include <iostream> //标准库头文件
    #include <iostream.h> //旧式的标准库头文件
    #include "IO.h" //用户自定义的头文件
    #include "../file.h" //UNIX下的父目录下的头文件
    #include "/usr/local/file.h" //UNIX下的完整路径
    #include "..file.h" //Dos下的父目录下的头文件
    #include "usrlocalfile.h" //Dos下的完整路径
    这里面有2个地方要注意:
    1、我们用<iostream>还是<iostream.h>?
        我们主张使用<iostream>,而不是<iostream.h>,为什么呢?我想你可能还记得我曾经给出过几点理由,这里我大致的说一下:首先,.h格式的头文件早在98年9月份就被标准委员会抛弃了,我们应该紧跟标准,以适合时代的发展。其次,iostream.h只支持窄字符集,iostream则支持窄/宽字符集。还有,标准对iostream作了很多的改动,接口和实现都有了变化。最后,iostream组件全部放入namespace std中,防止了名字污染。
    2、<io.h>和"io.h"的区别?
        其实他们唯一的区别就是搜索路径不同:
        对于#include <io.h> ,编译器从标准库路径开始搜索。
        对于#include "io.h" ,编译器从用户的工作路径开始搜索。


    五、编译控制指令
        这些指令的主要目的是进行编译时进行有选择的挑选,注释掉一些指定的代码,以达到版本控制、防止对文件重复包含的功能。使用格式,如下:

    1、如果identifier为一个定义了的符号,your code就会被编译,否则剔除

    #ifdef identifier
        your code
    #endif
    2、如果identifier为一个未定义的符号,your code就会被编译,否则剔除

    #ifndef identifier
        your code
    #endif
    3、如果expression非零,your code就会被编译,否则剔除

    #if expression
    	your code
    #endif
    4、如果identifier为一个定义了的符号,your code1就会被编译,否则your code2就会被编译

    #ifdef identifier
    	your code1
    #else
    	your code2
    #endif
    5、如果epression1非零,就编译your code1,否则,如果expression2非零,就编译your code2,否则,就编译your code3

    #if expressin1
    	your code1
    #elif expression2 //呵呵,elif
    	your code2
    #else
    	your code3
    #enif

    六、其他预编译指令
        除了上面我们说的集中常用的编译指令,还有3种不太常见的编译指令:#line、#error、#pragma,我们接下来就简单的谈一下。
    1、#line的语法如下:
        #line number filename
        例如:#line 30 a.h 其中,文件名a.h可以省略不写。

        这条指令可以改变当前的行号和文件名,例如上面的这条预处理指令就可以改变当前的行号为30,文件名是a.h。初看起来似乎没有什么用,不过,他还是有点用的,那就是用在编译器的编写中,我们知道编译器对C++源码编译过程中会产生一些中间文件,通过这条指令,可以保证文件名是固定的,不会被这些中间文件代替,有利于进行分析。


    2、#error语法如下:
        #error info
    例如:

    #ifndef UNIX
    #error This software requires the UNIX OS.
    #endif
        这条指令主要是给出错误信息,上面的这个例子就是,如果没有在UNIX环境下,就会输出This software requires the UNIX OS.然后诱发编译器终止。所以总的来说,这条指令的目的就是在程序崩溃之前能够给出一定的信息。

    3、#pragma
        它是非统一的,他要依靠各个编译器生产者,例如,在SUN C++编译器中:

    #progma align 8 (name, val)// 把name和val的起始地址调整为8个字节的倍数
    char name[9];
    double val;
    //或是如下用法:
    #progma init (MyFunction)//在程序执行开始,调用函数MyFunction
    

    七、预定义标识符
    为了处理一些有用的信息,预处理定义了一些预处理标识符,虽然各种编译器的预处理标识符不尽相同,但是他们都会处理下面的4种:
    __FILE__ 正在编译的文件的名字
    __LINE__ 正在编译的文件的行号
    __DATE__ 编译时刻的日期字符串,例如: "25 Dec 2000"
    __TIME__ 编译时刻的时间字符串,例如: "12:30:55"
    例如:cout<<"The file is :"<<__FILE__"<<"! The lines is:"<<__LINE__<<endl;


    八、预处理何去何从
        如何取代#include预处理指令,我们在这里就不再一一讨论了。C++并没有为#include提供替代形式,但是namespace提供了一种作用域机制,它能以某种方式支持组合,利用它可以改善#include的行为方式,但是我们还是无法取代#include。
        #progma应该算是一个可有可无的预处理指令,按照C++之父Bjarne的话说,就是:"#progma被过分的经常的用于将语言语义的变形隐藏到编译系统里,或者被用于提供带有特殊语义和笨拙语法的语言扩充。”
        对于#ifdef,我们仍然束手无策,就算是我们利用if语句和常量表达式,仍然不足以替代她,因为一个if语句的正文必须在语法上正确,满足类检查,即使他处在一个绝不会被执行的分支里面。


    转自:http://blog.csdn.net/bzhxuexi/article/details/26473317

    展开全文
  • 预编译又叫预处理预编译不是编译,而是编译前的处理。这个操作是在正式编译之前由系统自动完成的。 1、C语言源文件要经过编译、链接才能生成可执行程序: 1) 编译(Compile)会将源文件(.c文件)转换为目标文件...

    一、预编译

    预编译又叫预处理。预编译不是编译,而是编译前的处理。这个操作是在正式编译之前由系统自动完成的。

    1、C语言源文件要经过编译、链接才能生成可执行程序:
    1) 编译(Compile)会将源文件(.c文件)转换为目标文件。对于 VC/VS,目标文件后缀为.obj;对于GCC,目标文件后缀为.o

    编译是针对单个源文件的,一次编译操作只能编译一个源文件,如果程序中有多个源文件,就需要多次编译操作。

    2) 链接(Link)是针对多个文件的,它会将编译生成的多个目标文件以及系统中的库、组件等合并成一个可执行程序。

     

    2、在实际开发中,有时候在编译之前还需要对源文件进行简单的处理。

    这些在编译之前对源文件进行简单加工的过程,就称为预处理(即预先处理、提前处理)。

    预处理主要是处理以#开头的命令,例如#include <stdio.h>等。预处理命令要放在所有函数之外,而且一般都放在源文件的前面。

    3、预处理是C语言的一个重要功能,由预处理程序完成。当对一个源文件进行编译时,系统将自动调用预处理程序对源程序中的预处理部分作处理,处理完毕自动进入对源程序的编译。

     

    PS:C语言提供了多种预处理功能,如宏定义、文件包含、条件编译等,合理地使用它们会使编写的程序便于阅读、修改、移植和调试,也有利于模块化程序设计。

    二、#define

    C语言中,可以用 #define 定义一个标识符来表示一个常量。其特点是:定义的标识符不占内存,只是一个临时的符号,用来代替某个常量,预编译后这个符号就不存在了

     1、#define 定义标识符的一般形式为:

    #define  标识符  常量   //注意, 最后没有分号
    #define  P  3.14  //令符号P表示常量3.14
    

    #define 和 #include 一样,也是以“#”开头的。凡是以“#”开头的均为预处理指令,#define也不例外

    2、#define又称宏定义,标识符为所定义的宏名,简称宏。标识符的命名规则与前面讲的变量的命名规则是一样的。#define 的功能是将标识符定义为其后的常量。一经定义,程序中就可以直接用标识符来表示这个常量。是不是与定义变量类似?但是要区分开!变量名表示的是一个变量,但宏名表示的是一个常量。可以给变量赋值,但绝不能给常量赋值。

    展开全文
  • 预编译和预处理

    万次阅读 2011-09-13 11:00:38
    预编译和预处理以及编译选项的控制  总是对这三个不是很清晰,今天回来后准备转载,记在博客上。嘿嘿,我是不是很调皮啊 一 预编译: 为了增加编译速度往往要提前对一些头文件及代码进行编译,...

    预编译和预处理以及编译选项的控制  


    总是对这三个不是很清晰,今天回来后准备转载,记在博客上。嘿嘿,我是不是很调皮啊偷笑


    一 预编译:

    为了增加编译速度往往要提前对一些头文件及代码进行编译,然后给后面正式编译时使用,以节省开销。这些文件代码基本上不会更改,比如MFC的一些头文件以及一些必要的API使用代码,当然,你也可以把你自己的一部分代码封装起来到一个C或C++文件中,(比如在其中包含一些头文件或必要的代码什么的,然后在VC-C/C++--PreCompiled Headers里选择第三项Create compiled Header file)来指定为预编译头文件,这样就在以后的程序修改中编译时不会反复编译这部分。当然过多的使用预编译头文件会大大降低编译的速度,所以可以使用下面的预处理指令:

    #pragma hdrstop表示预编译头文件到此为止,后面的头文件不进行预编译。BCB可以预编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一些头文件。
    有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B要先于单元A编译。你可以用#pragma startup指定编译优先级,如果使用了#pragma package(smart_init) ,BCB就会根据优先级的大小先后编译。

    举例:主要是转别人的博文,感谢。

    今天在改一个很大的程序,慢慢看,慢慢改。突然发现一个.c文件,里面什么也没有,

    就几个头文件,我一看,我靠,这不是把简单的问题搞复杂了吗,随手删掉那个c文件。

    结果不能编译了,我靠:

    fatal error C1083: Cannot open precompiled header file: \'Debug/v13_3.pch\':

    No such file or directory

    怎么rebuild all都不行。

    上网查了一下,才搞懂了:

    ----------------总结------

    如果工程很大,头文件很多,而有几个头文件又是经常要用的,那么

    1。把这些头文件全部写到一个头文件里面去,比如写到preh.h

    2。写一个preh.c,里面只一句话:#include "preh.h"

    3。对于preh.c,在project setting里面设置creat precompiled headers,对于其他

    .c文件,设置use precompiled header file

    //

    哈哈

    我试了一下,效果很明显,不用precompiled header,编译一次我可以去上个厕所,用

    precompiled header,编译的时候,我可以站起来伸个懒腰,活动活动就差不多啦

    ---------转载的文章----------

    预编译头的概念:

    所谓的预编译头就是把一个工程中的那一部分代码,预先编译好放在一个文件里(通常是

    以.pch为扩展名的),这个文件就称为预编译头文件这些预先编译好的代码可以是任何的

    C/C++代码--------甚至是inline的函数,但是必须是稳定的,在工程开发的过程中不会

    被经常改变。如果这些代码被修改,则需要重新编译生成预编译头文件。注意生成预编

    译头文件是很耗时间的。同时你得注意预编译头文件通常很大,通常有6-7M大。注意及

    时清理那些没有用的预编译头文件。

    也许你会问:现在的编译器都有Time stamp的功能,编译器在编译整个工程的时候,它

    只会编译那些经过修改的文件,而不会去编译那些从上次编译过,到现在没有被修改过

    的文件。那么为什么还要预编译头文件呢?答案在这里,我们知道编译器是以文件为单

    位编译的,一个文件经过修改后,会重新编译整个文件,当然在这个文件里包含的所有

    头文件中的东西(.eg Macro, Preprocesser )都要重新处理一遍。VC的预编译头文件

    保存的正是这部分信息。以避免每次都要重新处理这些头文件。

    预编译头的作用:

    根据上文介绍,预编译头文件的作用当然就是提高便宜速度了,有了它你没有必要每次

    都编译那些不需要经常改变的代码。编译性能当然就提高了。

    预编译头的使用:

    要使用预编译头,我们必须指定一个头文件,这个头文件包含我们不会经常改变的

    代码和其他的头文件,然后我们用这个头文件来生成一个预编译头文件(.pch文件)

    想必大家都知道 StdAfx.h这个文件。很多人都认为这是VC提供的一个“系统级别”的

    ,编译器带的一个头文件。其实不是的,这个文件可以是任何名字的。我们来考察一个

    典型的由AppWizard生成的MFC Dialog Based 程序的预编译头文件。(因为AppWizard

    会为我们指定好如何使用预编译头文件,默认的是StdAfx.h,这是VC起的名字)。我们

    会发现这个头文件里包含了以下的头文件:

    #include <afxwin.h> // MFC core and standard components

    #include <afxext.h> // MFC extensions

    #include <afxdisp.h> // MFC Automation classes

    #include <afxdtctl.h> // MFC support for Internet Explorer 4

    Common Controls

    #include <afxcmn.h>

    这些正是使用MFC的必须包含的头文件,当然我们不太可能在我们的工程中修改这些头文

    件的,所以说他们是稳定的。

    那么我们如何指定它来生成预编译头文件。我们知道一个头文件是不能编译的。所以我

    们还需要一个cpp文件来生成.pch 文件。这个文件默认的就是StdAfx.cpp。在这个文件

    里只有一句代码就是:#include “Stdafx.h”。原因是理所当然的,我们仅仅是要它能

    够编译而已?D?D?D也就是说,要的只是它的.cpp的扩展名。我们可以用/Yc编译开关来指

    定StdAfx.cpp来生成一个.pch文件,通过/Fp编译开关来指定生成的pch文件的名字。打

    开project ->Setting->C/C++ 对话框。把Category指向Precompiled Header。在左边的

    树形视图里选择整个工程 

    Project Options(右下角的那个白的地方)可以看到 /Fp “debug/PCH.pch”,这就是指

    定生成的.pch文件的名字,默认的通常是 <工程名>.pch(我的示例工程名就是PCH)。

    然后,在左边的树形视图里选择StdAfx.cpp.//这时只能选一个cpp文件!

    这时原来的Project Option变成了 Source File Option(原来是工程,现在是一个文件

    ,当然变了)。在这里我们可以看到 /Yc开关,/Yc的作用就是指定这个文件来创建一个

    Pch文件。/Yc后面的文件名是那个包含了稳定代码的头文件,一个工程里只能有一个文

    件的可以有YC开关。VC就根据这个选项把 StdAfx.cpp编译成一个Obj文件和一个PCH文件

    然后我们再选择一个其它的文件来看看,//其他cpp文件

    在这里,Precomplier 选择了 Use ???一项,头文件是我们指定创建PCH 文件的stda

    fx.h

    文件。事实上,这里是使用工程里的设置,(如图1)/Yu”stdafx.h”。

    这样,我们就设置好了预编译头文件。也就是说,我们可以使用预编译头功能了。以

    下是注意事项:

    1):如果使用了/Yu,就是说使用了预编译,我们在每个.cpp文件的最开头,我强调一遍

    是最开头,包含 你指定产生pch文件的.h文件(默认是stdafx.h)不然就会有问题。如

    果你没有包含这个文件,就告诉你Unexpected file end. 如果你不是在最开头包含的,

    你自己试以下就知道了,绝对有很惊人的效果?..

    fatal error C1010: unexpected end of file while looking for precompiled

    header directive

    Generating Code...

    2)如果你把pch文件不小心丢了,编译的时候就会产生很多的不正常的行为。根据以上

    的分析,你只要让编译器生成一个pch文件。也就是说把 stdafx.cpp(即指定/Yc的那个

    cpp文件)从新编译一遍。当然你可以傻傻的 Rebuild All。简单一点就是选择那个cpp

    文件,按一下Ctrl + F7就可以了。不然可是很浪费时间的哦。

    二 预处理

    预处理指令中#PRAGMA是用得最多的,最复杂。所以直接拷别人总结的:

    pragma comment的使用
    该宏放置一个注释到对象文件或者可执行文件。

    #pragma comment( comment-type [,"commentstring"] )comment-type是一个预定义的标识符,指定注释的类型,应该是compiler,exestr,lib,linker之一。commentstring是一个提供为comment-type提供附加信息的字符串,
    Remarks:
    1、compiler:放置编译器的版本或者名字到一个对象文件,该选项是被linker忽略的。
    2、exestr:在以后的版本将被取消。
    3、lib:放置一个库搜索记录到对象文件中,这个类型应该是和commentstring(指定你要Liner搜索的lib的名称和路径)这个库的名字放在Object文件的默认库搜索记录的后面,linker搜索这个这个库就像你在命令行输入这个命令一样。你可以在一个源文件中设置多个库记录,它们在object文件中的顺序和在源文件中的顺序一样。如果默认库和附加库的次序是需要区别的,使用Z编译开关是防止默认库放到object模块。4、linker:指定一个连接选项,这样就不用在命令行输入或者在开发环境中设置了。只有下面的linker选项能被传给Linker.
    /DEFAULTLIB

    /EXPORT

    /INCLUDE

    /MANIFESTDEPENDENCY

    /MERGE

    /SECTION

    (1)/DEFAULTLIB:library/DEFAULTLIB 选项将一个 library 添加到 LINK 在解析引用时搜索的库列表。用 /DEFAULTLIB
    指定的库在命令行上指定的库之后和 .obj 文件中指定的默认库之前被搜索。
    忽略所有默认库 (/NODEFAULTLIB) 选项重写 /DEFAULTLIB:library。如果在两者中指定了相同的 library 名称,忽略库 (/NODEFAULTLIB:library) 选项将重写 /DEFAULTLIB:library。

    (2)/EXPORT:entryname[,@ordinal[,NONAME]][,DATA]


    使用该选项,可以从程序导出函数,以便其他程序可以调用该函数。也可以导出数据。通常在 DLL 中定义导出。entryname 是调用程序要使用的函数或数据项的名称。ordinal 在导出表中指定范围在 1 至 65,535 的索引;如果没有指定 ordinal,则 LINK 将分配一个。NONAME 关键字只将函数导出为序号,没有 entryname。

    DATA 关键字指定导出项为数据项。客户程序中的数据项必须用 extern __declspec(dllimport) 来声明。
    有三种导出定义的方法,按照建议的使用顺序依次为:

    源代码中的 __declspec(dllexport)

    .def 文件中的 EXPORTS 语句

    LINK 命令中的 /EXPORT 规范

    所有这三种方法可以用在同一个程序中。LINK 在生成包含导出的程序时还创建导入库,除非生成中使用了 .exp 文件。
    LINK 使用标识符的修饰形式。编译器在创建 .obj 文件时修饰标识符。如果 entryname 以其未修饰的形式指定给链接器(与其在源代码中一样),则 LINK 将试图匹配该名称。如果无法找到唯一的匹配名称,则 LINK 发出错误信息。当需要将标识符指定给链接器时,请使用 Dumpbin 工具获取该标识符的修饰名形式。

    (3)/INCLUDE:symbol
    /INCLUDE 选项通知链接器将指定的符号添加到符号表。

    若要指定多个符号,请在符号名称之间键入逗号 (,)、分号 (;) 或空格。在命令行上,对每个符号指定一次 /INCLUDE:symbol。
    链接器通过将包含符号定义的对象添加到程序来解析 symbol。该功能对于添包含不会链接到程序的库对象非常有用。用该选项指定符号将通过 /OPT:REF 重写该符号的移除。

    我们经常用到的是#pragma   comment(lib,"*.lib")这类的。#pragma   comment(lib,"Ws2_32.lib")表示链接Ws2_32.lib这个库。   和在工程设置里写上链入Ws2_32.lib的效果一样,不过这种方法写的   程序别人在使用你的代码的时候就不用再设置工程settings了

     

     

     

     


    #pragma C++
    解析#pragma指令
    在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。
    其格式一般为: #Pragma Para
    其中Para 为参数,下面来看一些常用的参数。

    (1)message 参数。 Message 参数是我最喜欢的一个参数,它能够在编译信息输出窗
    口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为:
    #Pragma message(“消息文本”)
    当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。
    当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。假设我们希望判断自己有没有在源代码的什么地方定义了_X86这个宏可以用下面的方法
    #ifdef _X86
    #Pragma message(“_X86 macro activated!”)
    #endif
    当我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示“_
    X86 macro activated!”。我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了

    (2)另一个使用得比较多的pragma参数是code_seg。格式如:
    #pragma co
    de_seg( ["section-name"[,"section-class"] ] )
    它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。

    (3)#pragma once (比较常用)
    只要在头文件的最开始加入这条指令就能够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用它。

    (4)#pragma hdrstop表示预编译头文件到此为止,后面的头文件不进行预编译。BCB可以预编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一些头文件。
    有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B要先于单元A编译。你可以用#pragma startup指定编译优先级,如果使用了#pragma package(smart_init) ,BCB就会根据优先级的大小先后编译。

    (5)#pragma resource "*.dfm"表示把*.dfm文件中的资源加入工程。*.dfm中包括窗体
    外观的定义。

    (6)#pragma warning( disable : 4507 34; once : 4385; error : 164 )
    等价于:
    #pragma warning(disable:4507 34) // 不显示4507和34号警告信息
    #pragma warning(on
    ce:4385) // 4385号警告信息仅报告一次
    #pragma warning(error:164) // 把164号警告信息作为一个错误。
    同时这个pragma warning 也支持如下格式:
    #pragma warning( push [ ,n ] )
    #pragma warning( pop )
    这里n代表一个警告等级(1---4)。
    #pragma warning( push )保存所有警告信息的现有的警告状态。
    #pragma warning( push, n)保存所有警告信息的现有的警告状态,并且把全局警告
    等级设定为n。
    #pragma warning( pop )向栈中弹出最后一个警告信息,在入栈和出栈之间所作的
    一切改动取消。例如:
    #pragma warning( push )
    #pragma warning( disable : 4705 )
    #pragma warning( disable : 4706 )
    #pragma warning( disable : 4707 )
    //.......
    #pragma warning( pop )
    在这段代码的最后,重新保存所有的警告信息(包括4705,4706和4707)。
    (7)pragma comment(...)
    该指令将一个注释记录放入一个对象文件或可执行文件中。
    常用的lib关键字,可以帮我们连入一个库文件。

    (8)#pragma pack()
    我们知道在VC中,对于想结构体Struct这样的类型,VC采用8字节对齐的方式,如果我们不想使用8字节对齐(在网络变成中经常需要这样),我们可以在结构体前面加上
    #pragma pack(1)
    struct
    {
    ......
    }
    #pragma pack( )

    以下是另一个转载:

    在vc6的时代头文件一般使用ifndef define endif
    在vc7的时代头文件一般成了pragma on
    ce
    不知道有没有人深究其中的意义
    为什么有这样的代码,是为了头文件不被重复引用,那样编译器抱错的,这两种方法都是同样的目的,有没有区别呢?
    还是举例来说明,可能有好几个库,每个库内部可能都有public.h这个文件,如果使用
    ifndef public_h
    define public_h
    ...
    endif
    那么当一个文件同时引用两个这样的库时,后一个库里的文件就不被编译了,而pragma on
    ce可以保证文件只被编译一次
    看起来pragma on
    ce比ifndef define endif要好,那么ifndef define endif
    的地方都pragma on
    ce好了。今天碰到了又一个例子,比如你有一个zlib.h在几个库都用到,而为了方便,把zlib每个目录下copy了一分,因为这个文件不会作修改,已经很完整了,这个时候如果使用pragma once,就会重复定义,看来ifndef define endif还是又派上用场的地方。
    所以对于公有或者接口的文件,使用ifndef define endif,对于内部的文件使用pragma on
    ce.

    #pragma once 与 #ifndef #define #endif 的区别

    对于#pragma once,根据MSDN解说,能够防止一个文件被多次包含。与#ifndef #define #endif形式的文件保护相比,前者是平台相关的,可移植性比较差,但是它效率更高,因为它不需要去打开包含的文件,就可以判断这个文件有没有被包含。当然这个工作是系统帮我们完成的。
    后者的优点在于它是语言相关的特性,所以可移植性好。但是在包含一个文件的时候,只有打开这个文件,根据文件的保护宏是否已经被定义来判断此文件是否已经被包含过。效率相对较低。当然在#i nclude的时候,程序员也可以自己判断所要包含的文件的保护宏是否已经被定义,来决定是否要包含这个文件。类似下面的代码:
    #ifndef FILE_H_#i nclude "file.h"#endif这样作可以得到较高的效率,而且保证可移植性。但是文件之间的依赖性较高,如果一个文件的保护宏改变的话,所有使用如上形式包含这个文件的文件都要修改。有悖于模块化的思想。


    #pragma da
    ta_seg用法总结 (2008-09-05 12:54:54)
    标签:杂谈   分类:编程

        Windows在一个Win32程序的地址空间周围筑了一道墙。通常,一个程序的地址空间中的数据是私有的,对别的程序而言是不可见的。但是执行STRPROG的多个执行实体表示了STRLIB在程序的所有执行实体之间共享数据是毫无问题的。当您在一个STRPROG窗口中增加或者删除一个字符串时,这种改变将立即反映在其它的窗口中。

    在全部例程之间,STRLIB共享两个变量:一个字符数组和一个整数(记录已储存的有效字符串的个数)。STRLIB将这两个变量储存在共享的一个特殊内存区段中:

    #pragma    data_seg ("shared")
    int      iTotal = 0 ; 

    WCHAR    szStrings [MAX_STRINGS][MAX_LENGTH + 1] = { '\0' } ;
    #pragma       da
    ta_seg ()       

    第一个#pragma叙述建立数据段,这里命名为shared。您可以将这段命名为任何一个您喜欢的名字。在这里的#pragma叙述之后的所有初始化了的变量都放在shared数据段中。第二个#pragma叙述标示段的结束。对变量进行专门的初始化是很重要的,否则编译器将把它们放在普通的未初始化数据段中而不是放在shared中。

    连结器必须知道有一个「shared」共享数据段。在「Project Settings」对话框选择「Link」页面卷标。选中「STRLIB」时在「Project Options」字段(在Release和Debug设定中均可),包含下面的连结叙述:

    /SECTION:shared,RWS

    字母RWS表示段具有读、写和共享属性。或者,您也可以直接用DLL原始码指定连结选项,就像我们在STRLIB.C那样:

    #pragma comment(linker,"/SECTION:shared,RWS")
    共享的内存段允许iTotal变量和szStrings字符串数组在STRLIB的所有例程之间共享。因为MAX_STRINGS等于256,而MAX_LENGTH等于63,所以,共享内存段的长度为32,772字节-iTotal变量需要4字节,256个指针中的每一个都需要128字节。

    在Win16环境中,DLL的全局数据对每个载入它的进程来说都是相同的;而在Win32环境中,情况却发生了变化,DLL函数中的代码所创建的任何对象(包括变量)都归调用它的线程或进程所有。当进程在载入DLL时操作系统自动把DLL地址映射到该进程的私有空间,也就是进程的虚拟地址空间,而且也复制该DLL的全局数据的一份拷贝到该进程空间。也就是说每个进程所拥有的相同的DLL的全局数据,它们的名称相同,但其值却并不一定是相同的,而且是互不干涉的。因此,在Win32环境下要想在多个进程中共享数据,就必须进行必要的设置。在访问同一个Dll的各进程之间共
    享存储器是通过存储器映射文件技术实现的。也可以把这些需要共享的数据分离出来,放置在一个独立的数据段里,并把该段的属性设置为共享。必须给这些变量赋初值,否则编译器会把没有赋初始值的变量放在一个叫未被初始化的数据段中。
    #pragma da
    ta_seg预处理指令用于设置共享数据段。例如:
    #pragma da
    ta_seg("SharedDataName")
    HHOOK hHook=NULL;
    #pragma da
    ta_seg()

     在#pragma data_seg("SharedDataName")和#pragma data_seg()之间的所有变量将被访问该Dll的所有进程看到和共享。再加上一条指令

    #pragma comment(linker,"/section:.SharedDataName,rws"),

    那么这个数据节中的数据可以在所有DLL的实例之间共享。所有对这些数据的操作都针对同一个实例的,而不是在每个进程的地址空间中都有一份。

       1.#pragma data_seg()一般用于DLL中。也就是说,在DLL中定义一个共享的,有名字的数据段。最关键的是:这个数据段中的全局变量可以被多个进程共享。否则多个进程之间无法共享DLL中的全局变量。

       2.共享数据必须初始化,否则微软编译器会把没有初始化的数据放到.BSS段中,从而导致多个进程之间的共享行为失败。

       3.你所谓的结果正确是一种错觉。如果你在一个DLL中这么写:

    #pragma data_seg("MyData")

     int g_Value; // Note that the global is not initialized.

     

    #pragma data_seg()

    DLL提供两个接口函数:

    int GetValue()
    {
         return g_Value;
    }

    void SetValue(int n)
    {
         g_Value = n;
    }

    然后启动两个进程A和B,A和B都调用了这个DLL,假如A调用了SetValue(5); B接着调用int m = GetValue(); 那么m的值不一定是5,而是一个未定义的值。因为DLL中的全局数据对于每一个调用它的进程而言,是私有的,不能共享的。假如你对g_Value进行了初始化,那么g_Value就一定会被放进MyData段中。换句话说,如果A调用了SetValue(5); B接着调用int m = GetValue(); 那么m的值就一定是5!这就实现了跨进程之间的数据通信!


    下面看一个实际应用,用共享数据来统计应用程序启动的次数,并作相应的处理。

     

    在应用程序的入口处:
    //控制应用程序只能启动一次
    #pragma da
    ta_seg("flag_data")
       int count=0;
    #pragma da
    ta_seg()
    #pragma comment(linker,"/SECTION:flag_da
    ta,RWS")

    程序中:
       if(count>1)
         {
          MessageBox("已经启动了一个应用程序","Warning",MB_OK);
          return FLASE;
    }
       count++;

     


    Visual C++ 6.0编译指示收藏
    新一篇: C++ 中的cast(显式类型转换) | 旧一篇: 看一个人是否快乐,不要看笑容
    Document Source:

    Pragma Directives, Preprocessor Reference, Visual C++ Programmer Guide.

     

    每种C和C++的实现支持对其宿主机或操作系统唯一的功能。例如,一些程序需要精确控制超出数据所在的储存空间,或着控制特定函数接受参数的方式。#pragma指示使每个编译程序在保留C和C++语言的整体兼容性时提供不同机器和操作系统特定的功能。编译指示被定义为机器或操作系统特定的,并且通常每种编译程序是不同的。

    语法:

    #pragma token_string

    “token_string”是一系列字符用来给出所需的特定编译程序指令和参数。数字符号“#”必须是包含编译指令的行中第一个非空白字符;而空白字符可以隔开数字符号“#”和关键字“pragma”。在#pragma后面,写任何翻译程序能够作为预处理符号分析的文本。#pragma的参数类似于宏扩展。

    如果编译程序发现它不认得一个编译指示,它将给出一个警告,可是编译会继续下去。

    为了提供新的预处理功能,或者为编译程序提供由实现定义的信息,编译指示可以用在一个条件语句内。C和C++编译程序可以识别下列编译程序指令。

    alloc_text
     comment
     init_seg*
     optimize
     
    auto_inline
     component
     inline_depth
     pack
     
    bss_seg
     da
    ta_seg
     inline_recursion
     pointers_to_members*
     
    check_stack
     function
     intrinsic
     setlocale
     
    co
    de_seg
     hdrstop
     message
     vtordisp*
     
    const_seg
     include_alias
     on
    ce
     warning
     

    *仅用于C++编译程序。

    1  alloc_text
    #pragma alloc_text( "textsection", function1, ... )

    命名特别定义的函数驻留的代码段。该编译指示必须出现在函数说明符和函数定义之间。

    alloc_text编译指示不处理C++成员函数或重载函数。它仅能应用在以C连接方式说明的函数——就是说,函数是用extern "C"连接指示符说明的。如果你试图将这个编译指示应用于一个具有C++连接方式的函数时,将出现一个编译程序错误。

    由于不支持使用__based的函数地址,需要使用alloc_text编译指示来指定段位置。由textsection指定的名字应该由双引号括起来。

    alloc_text编译指示必须出现在任何需要指定的函数说明之后,以及这些函数的定义之前。

    在alloc_text编译指示中引用的函数必须和该编译指示处于同一个模块中。如果不这样做,使以后一个未定义的函数被编译到一个不同的代码段时,错误会也可能不会被捕获。即使程序一般会正常运行,但是函数不会分派到应该在的段。

    alloc_text的其它限制如下:

    它不能用在一个函数内部。

    它必须用于函数说明以后,函数定义以前。

    2  auto_inline
    #pragma auto_inline( [{on | off}] )

    当指定off时将任何一个可以被考虑为作为自动嵌入扩展候选的函数排除出该范围。为了使用auto_inline编译指示,将其紧接着写在一个函数定义之前或之后(不是在其内部)。该编译指示将在其出现以后的第一个函数定义开始起作用。auto_inline编译指示对显式的inline函数不起作用。

    3  bss_seg
    #pragma da
    ta_seg( ["section-name"[, "section-class"] ] )

    为未初始化数据指定缺省段。data_seg编译指示除了工作于已初始化数据而不是未初始化的以外具有一样的效果。在一些情况下,你能使用bss_seg将所有未初始化数据安排在一个段中来加速你的装载时间。

    #pragma bss_seg( "MY_DATA" )

    将导致把#pragma语句之后的未初始化的数据安排在一个叫做MY_DATA的段中。

    用bss_seg编译指示分配的数据不包含任何关于其位置的信息。

    第二个参数section-class是用于兼容2.0版本以前的Visual C++的,现在将忽略它。

    4  check_stack
    #pragma check_stack([ {on | off}] )

    #pragma check_stack{+ | –}

    如果指定off(或者“-”)指示编译程序关闭堆栈探测,或者指定on(或“+”)打开堆栈探测。如果没有给出参数,堆栈探测将根据默认设置决定。该编译指示将在出现该指示之后的第一个函数开始生效。堆栈探测既不是宏和能够生成嵌入代码函数的一部分。

    如果你没有给出check-_stack编译指示的参数,堆栈检查将恢复到在命令行指定的行为。详细情况见编译程序参考。#pragma check_stack和/Gs选项的互相作用情况在表2.1中说明。

    表 2.1 使用check_stack编译指示

    编译指示
     用/Gs选项编译?
     行为
     
    #pragma check_stack()或#pragma check_stack
     是
     后续的函数关闭堆栈检查
     
    #pragma check_stack()或#pragma check_stack
     否
     后续的函数打开堆栈检查
     
    #pragma check_stack(on)或#pragma check_stack(+)
     是或者否
     后续的函数打开堆栈检查
     
    #pragma check_stack(off)或#pragma check_stack(-)
     是或者否
     后续的函数关闭堆栈检查
     

    5  code_seg
    #pragma co
    de_seg( ["section-name"[,"section-class"] ] )

    指定分配函数的代码段。code_seg编译指示为函数指定默认的段。你也能够像段名一样指定一个可选的类名。使用没有段名字符串的#pragma code_seg将恢复分配到编译开始时候的状态。

    6  const_seg
    #pragma const_seg( ["section-name"[, "section-class"] ] )

    指定用于常量数据的默认段。data_seg编译指示除了可以工作于所有数据以外具有一样的效果。你能够使用该编译指示将你的常量数据保存在一个只读的段中。

    #pragma const_seg( "MY_DATA" )

    导致在#pragma语句后面的常量数据分配在一个叫做MY_DATA的段中。

    用const_seg编译指示分配的数据不包含任何关于其位置的信息。

    第二个参数section-class是用于兼容2.0版本以前的Visual C++的,现在将忽略它。

    7  comment
    #pragma comment( comment-type [, commentstring] )

    将描述记录安排到目标文件或可执行文件中去。comment-type是下面说明的五个预定义标识符中的一个,用来指定描述记录的类型。可选的commentstring是一个字符串文字值用于为一些描述类型提供附加的信息。因为commentstring是一个字符串文字值,所以它遵从字符串文字值的所有规则,例如换码字符、嵌入的引号(")和联接。

    7-1
     
    compiler
    在目标文件中放置编译程序名和版本号。该描述记录被连接程序忽略。如果你为这个记录类型提供一个commentstring参数,编译程序将生成一个警告。

    7-2
     
    exestr
    将commentstring放置到目标文件中去。在连结时,这个字符串再被放到可执行文件去中。当可执行文件被装载时这个字符串不会被装入内存,然而,它可以被一个能够在文件中搜索可打印字符串的程序找到。该描述记录的一个用处是在可执行文件中嵌入版本号或者类似的信息。

    7-3
     
    lib
    将一个库搜索记录放置到目标文件中去。该描述类型必须有包含你要连接程序搜索的库名(和可能的路径)的commentstring参数。因为在目标文件中该库名先于默认的库搜索记录,所以连接程序将如同你在命令行输入这些库一样来搜索它们。你可以在一个源文件中放置多个库搜索记录,每个记录将按照它们出现在源文件中的顺序出现在目标文件中。

    7-4
     
    linker
    在目标文件中放置连接程序选项。你可以用这个描述类型指定连接程序选项来代替在Project Setting对话框中Link页内的选项。例如,你可以指定/include选项以强迫包含一个符号:

    #pragma comment(linker, "/include:__mySymbol")

    7-5
     
    user
    在目标文件中包含一个普通描述记录。commentstring参数包含描述的文本。该描述记录将被连接程序忽略。

     

    下面的编译指示导致连接程序在连接时搜索EMAPI.LIB库。连接程序首先在当前工作目录然后在LIB环境变量指定的路径中搜索。

    #pragma comment( lib, "emapi" )

    下面的编译指示导致编译程序将其名字和版本号放置到目标文件中去。

    The following pragma causes the compiler to place the name and version number of the compiler in the object file:

    #pragma comment( compiler )

    注意,对于具有commentstring参数的描述记录,你可以使用其它用作字符串文字量的宏来提供宏扩展为字符串文字量。你也能够联结任何字符串文字量和宏的组合来扩展成为一个字符串文字量。例如,下面的语句是可以接受的:

    #pragma comment( user, "Compiled on " __DATE__ " at " __TIME__ )

    8  component
    #pragma component( browser, { on | off }[, references [, name ]] )

    #pragma component( minrebuild, on | off )

     

    从源文件内控制浏览信息和依赖信息的收集。

    8-1
     
    浏览信息(
    Browser

    你可以将收集打开或关闭,你也可以指定收集时忽略特别的名字。

    使用on或off在编译指示以后控制浏览信息的收集。例如:

    #pragma component(browser, off)

    终止编译程序收集浏览信息。

    注意,为了用这个编译指示打开浏览信息的收集,必须先从Project Setting对话框或者命令行允许浏览信息。

    references选项可以有也可以没有name参数。使用没有name参数的references选项将打开或者关闭引用信息的收集(然而继续收集其它浏览信息)。例如:

    #pragma component(browser, off, references)

    终止编译程序收集引用信息。

    使用有name和off参数的references选项将阻止从浏览信息窗口中出现引用到的名字。用这个语法将忽略你不感兴趣的名字和类型从而减少浏览信息文件的大小。例如:

    #pragma component(browser, off, references, DWORD)

    从这一点以后忽略DWORD的引用。你能够用on恢复DWORD的引用收集:

    #pragma component(browser, on, references, DWORD)

    这是唯一的方法可以恢复收集指定名字的引用,你必须显式地打开任何你关闭的名字。

    为了防止预处理程序扩展名字(就像扩展NULL到0),用引号括起来:

    #pragma component(browser, off, references, "NULL")

    8-2
     
    最小化重建(
    Minimal Rebuild

    Visual C++的最小化重建功能要求编译程序创建并保存需要大量磁盘空间的C++类依赖信息。为了节省磁盘空间,你能够在你不需要收集依赖信息时使用#pragma component(minrebuild,off),例如,没有改变过头文件。在未修改过的类之后插入#pragma component(minrebuild,on)重新打开依赖信息。

    详见Enable Minimal Rebuild(/Gm)编译程序选项。

    9  data_seg
    #pragma da
    ta_seg( ["section-name"[, "section-class"] ] )

    指定数据的默认段。例如:

    #pragma data_seg( "MY_DATA" )

    导致在#pragma语句后分配的数据保存在一个叫做MY_DATA的段中。

    用data_seg编译指示分配的数据不包含任何关于其位置的信息。

    第二个参数section-class是用于兼容2.0版本以前的Visual C++的,现在将忽略它。

    10  function
    #pragma function( function1 [, function2, ...] )

    指定必须生成对编译指示中参数列表内函数的调用。如果你使用intrinsic编译指示(或者/Oi)来告诉编译程序生成内含函数(内含函数如同嵌入代码一样生成,不作为一个函数调用),你能够用function编译指示显式地强迫函数调用。当遇到一个function编译指示,它将在其后面遇到的第一个包含有内含函数的函数定义处生效。其持续作用到源文件的尾部或者出现对同一个内含函数指定intrinsic编译指示。function编译指示只能用于函数外——在全局层次。

    为了列出具有内含形式的函数表,参见#pragma intrinsic。

    11  hdrstop
    #pragma hdrstop [( "filename" )] 

    控制预编译头文件的工作方式。filename是要使用或者创建(依赖于是否指定了/Yu或/Yc)预编译头文件的名字。如果 filename不包括一个指定路径,将假定预编译头文件和源文件处于同一个目录中。当指定自动预编译头文件选项/YX时,所有指定的文件名将被忽略。

    如果有/YX或者/Yc选项,而且C或C++文件包含了一个hdrstop编译指示时,编译程序保存编译指示之前的编译状态。编译指示之后的编译状态不被保存。

    hdrstop编译选项不能出现在一个头文件内。它只能出现在源文件的文件级,它也不能出现在任何数据或者函数的说明或定义之中。

    注意,除非指定没有文件名的/YX选项或者/Yu或/Yc选项,否则hdrstop编译指示将被忽略。

    用一个文件名命名要保存编译状态的预编译头文件。在hdrstop和filename之间的空格是可选的。在hdrstop编译指示中的文件名是一个字符串,这样它服从于C或C++的字符串规则。特别的,你必须像下面例子里面显示的用引号括起来。

    #pragma hdrstop( "c:\projects\include\myinc.pch" )

    预编译头文件的文件名按照如下规则决定,按照优先次序:

    /Fp编译程序选项的参数;

    由#pragma hdrstop的filename参数;

    原文件名的基本文件名加上.PCH扩展名。

    12  include_alias
    #pragma include_alias( "long_filename", "short_filename" )

    #pragma include_alias( <long_filename>, <short_filename> )

    指定作为long_filename别名的short_filename。一些文件系统允许超出8.3FAT文件系统限制的长头文件名。编译程序不能简单地将长文件名截断为8.3名字,因为长头文件名的前8个字符可能不是唯一的。无论何时编译程序遇到long_filename串,它代替short_filename,并且用short_filename搜索头文件。这个编译指示必须出现在相应的#include指示之前。例如:

    // First eight characters of these two files not unique.

    #pragma include_alias( "AppleSystemHeaderQuickdraw.h", "quickdra.h" )

    #pragma include_alias( "AppleSystemHeaderFruit.h", "fruit.h" )

    #pragma include_alias( "GraphicsMenu.h", "gramenu.h" )

     

    #include "AppleSystemHeaderQuickdraw.h"

    #include "AppleSystemHeaderFruit.h"

    #include "GraphicsMenu.h"

    这个别名在搜索时精确匹配,包括拼写和双引号、尖括号。include_alias编译指示在文件名上执行简单的字符串匹配,不进行其它的文件名验证。例如,给出下列指示:

    #pragma include_alias("mymath.h", "math.h")

    #include "./mymath.h"

    #include "sys/mymath.h"

    并不执行别名替代,因为头文件名字符串没有精确匹配。另外,在/Yu,/Yc和/YX编译程序选项,或hdrstop编译指示中作为参数的头文件名不被替换。例如,如果你的源文件包含下列指示:

    #include <AppleSystemHeaderStop.h>

    相应的编译程序选项必须是:

    /YcAppleSystemHeaderStop.h

    你能够用include-_alias编译指示将任何头文件映射到其它文件。例如:

    #pragma include_alias( "api.h", "c:\version1.0\api.h" )

    #pragma include_alias( <stdio.h>, <newstdio.h> )

    #include "api.h"

    #include <stdio.h>

    不要混淆用双引号和尖括号括起来的文件名。例如,给出上面的#pragma include_alias指示时,在下面的#include指示中编译程序不执行替换。

    #include <api.h>

    #include "stdio.h"

    还有,下面的指示将产生一个错误:

    #pragma include_alias(<header.h>, "header.h")  // Error

    注意,在错误信息中报告的文件名,或者预定义宏__FILE__的值,是执行替换以后的文件名。例如,在下列指示之后:

    #pragma include_alias( "VeryLongFileName.H", "myfile.h" )

    #include "VeryLongFileName.H"

    文件VeryLongFileName.H产生下列错误信息:

    myfile.h(15) : error C2059 : syntax error

    还要注意的是不支持传递性。给出下面的指示:

    #pragma include_alias( "one.h", "two.h" )

    #pragma include_alias( "two.h", "three.h" )

    #include "one.h"

    编译程序将搜索two.h而不是three.h。

    13  init_seg
    C++特有

    #pragma init_seg({ compiler | lib | user | "section-name" [, "func-name"]} )

    指定影响启动代码执行的关键字或代码段。因为全局静态对象的初始化可以包含执行代码,所以你必须指定一个关键字来定义什么时候构造对象。在使用需要初始化的动态连接库(DLL)或程序库时使用init_seg编译指示是尤其重要的。

    init_seg编译指示的选项有:

    13-1
     
    compiler
    由Microsoft C运行时间库保留。在这个组中的对象将第一个构造。

    13-2
     
    lib
    用于第三方类库开发者的初始化。在这个组中的对象将在标记为构造compiler的对象之后,其它对象之前构造。

    13-3
     
    user
    用于任何其它用户。在这个组中的对象将最后构造。

    13-4
     
    section-name
    允许显式地指定初始化段。在用户指定的section-name中的对象将不会隐式地构造,而它们的地址将会被放置在由section-name命名的段中。

    13-5
     
    func-name
    指定当程序退出时,作为atexit函数调用的函数。这个函数必须具有和atexit函数相同的形式:

    int funcname(void (__cdecl *)(void));

    如果你需要延迟初始化,你能够选择指定显式的段名。随后你必须调用每个静态对象的构造函数。

    14  inline_depth
    #pragma inline_depth( [0... 255] )

    通过控制能够被扩展的一系列函数调用(从0到255次)来控制嵌入函数扩展的发生次数,这个编译指示控制用inline,__inline标记的或在/Ob2选项下能自动嵌入的嵌入函数。

    inline_depth编译指示控制能够被扩展的一系列函数调用。例如,如果嵌入深度是4,并且如果A调用B然后调用C,所有的3次调用都将做嵌入扩展。然而,如果设置的最近一次嵌入深度是2,则只有A和B被扩展,而C仍然作为函数调用。

    为了使用这个编译指示,你必须设置编译程序选项/Ob为1或者2。用这个编译指示指定的深度设定在该指示后面的第一个函数开始生效。如果你在括号内不指定一个值,inline_depth设置嵌入深度到默认值8。

    在扩展时,嵌入深度可以被减少而不能被增加。如果嵌入深度是6,同时在扩展过程中预处理程序遇到一个inline_depth编译指示设置为8,则深度保持为6。

    嵌入深度0将拒绝嵌入扩展,深度255将设置在嵌入扩展时没有限制。如果用一个没有指定值的编译指示,则使用为默认值。

    15  inline_recursion
    #pragma inline_recursion( [{on | off}] )

    控制直接或者相互间的递归函数调用式的嵌入扩展。用这个编译指示控制用inline,__inline标记的或在/Ob2选项下能自动嵌入的嵌入函数。使用这个编译指示需要设置编译程序选项/Ob为1或者2。默认的inline_recursion状态是off。这个编译指示在出现该编译指示之后第一个函数调用起作用,并不影响函数的定义。

    inline_recursion编译指示控制如何扩展递归函数。如果inline_recursion是off,并且如果一个嵌入函数调用了它自己(直接的或者间接的),函数将仅仅扩展一次。如果inline_recursion是on,函数将扩展多次直到达到inline_depth的值或者容量限制。

    16  intrinsic
    #pragma intrinsic( function1 [, function2, ...] )

    指定对在编译指示参数表中函数调用是内含的。编译程序像嵌入代码一样生成内含函数,而不是函数调用。下面列出了具有内含形式的库函数。一旦遇到intrinsic编译指示,它从第一个包含指定内含函数的函数定义开始起作用。作用持续到源文件尾部或者出现包含相同内含函数的function编译指示。intrinsic编译指示只能用在函数定义外——在全局层次。

    下列函数具有内含形式:

    _disable
     _enable
     _inp
     _inpw
     _lrotl
     _lrotr
     
    _outp
     _outpw
     _rotl
     _rotr
     _strset
     abs
     
    fabs
     labs
     memcmp
     memcpy
     memset
     strcat
     
    strcmp
     strcpy
     strlen
     
     
     
     

    使用内含函数的程序更快,因为它们没有函数调用的额外代价,然而因为有附加的代码生成,可能比较大。

    注意,_alloca和setjmp函数总是内含的,这个行为不受intrinsic编译指示影响。

    下列浮点函数没有内含形式。然而它们具有直接将参数通过浮点芯片传送而不是推入程序堆栈的版本。

    acos
     asin
     cosh
     fmod
     pow
     sinh
     
    tanh
     
     
     
     
     
     

    当你同时指定/Oi和/Og编译程序选项(或者任何包含/Og,/Ox,/O1和/O2的选项)时下列浮点函数具有真正的内含形式。

    atan
     exp
     log10
     sqrt
     atan2
     log
     
    sin
     tan
     cos      
     
     
     
     

    你可以用编译程序选项/Op或/Za来覆盖真内含浮点选项的生成。在这种情况下,函数会像一般库函数一样被生成,同时直接将参数通过浮点芯片传送而不是推入程序堆栈。

    17  message
    #pragma message( messagestring )

    不中断编译,发送一个字符串文字量到标准输出。message编译指示的典型运用是在编译时显示信息。

    下面的代码段用message编译指示在编译过程中显示一条信息:

    #if _M_IX86 == 500

    #pragma message( "Pentium processor build" )

    #endif

    messagestring参数可以是一个能够扩展成字符串文字量的宏,并且你能够用字符串文字量和宏的任何组合来构造。例如,下面的语句显示被编译文件的文件名和文件最后一次修改的日期和时间。

    #pragma message( "Compiling " __FILE__ )

    #pragma message( "Last modified on " __TIMESTAMP__ )

    18  once
    #pragma on
    ce

    指定在创建过程中该编译指示所在的文件仅仅被编译程序包含(打开)一次。该编译指示的一种常见用法如下:

    //header.h

    #pragma once

    // Your C or C++ code would follow:

    19  optimize
    仅在专业版和企业版中存在

    #pragma optimize( "[optimization-list]", {on | off} )

    代码优化仅有Visual C++专业版和企业版支持。详见Visual C++ Edition。

    指定在函数层次执行的优化。optimize编译选项必须在函数外出现,并且在该编译指示出现以后的第一个函数定义开始起作用。on和off参数打开或关闭在optimization-list指定的选项。

    optimization-list能够是0或更多个在表2.2中给出的参数:

    表 2.2   optimize编译指示的参数

    参数
     优化类型
     
    a
     假定没有别名。
     
    g
     允许全局优化。
     
    p
     增强浮点一致性。
     
    s 或 t
     指定更短或者更快的机器代码序列。
     
    w
     假定在函数调用中没有别名。
     
    y
     在程序堆栈中生成框架指针。
     

    这些和在/O编译程序选项中使用的是相同的字母。例如:

    #pragma optimize( "atp", on )

    用空字符串("")的optimize编译指示是一种特别形式。它要么关闭所有的优化选项,要么恢复它们到原始(或默认)的设定。

    #pragma optimize( "", off )

    .

    .

    .

    #pragma optimize( "", on )

    20  pack
    #pragma pack( [ n] )

    指定结构和联合成员的紧缩对齐。尽管用/Zp选项设定整个翻译单元的结构和联合成员的紧缩对齐,可以用pack编译指示在数据说明层次设定紧缩对齐。从出现该编译指示后的第一个结构或者联合说明开始生效。这个编译指示不影响定义。

    当你使用#pragma pack(n),其中n是1,2,4,8或者16,第一个以后的每个结构成员保存在较小的成员类型或者n字节边界上。如果你使用没有参数的#pragma pack,结构成员将被紧缩到由/Zp指定的值。默认的/Zp紧缩的大小是/Zp8。

    编译程序还支持下面的增强语法:

    #pragma pack( [ [ { push | pop}, ] [  identifier, ] ] [ n ] )

    该语法允许你将使用不同紧缩编译指示的组件合并到同一个翻译单元内。

    每次出现有push参数的pack编译指示将保存当前的紧缩对齐值到一个内部的编译程序堆栈。编译指示的参数列表从左向右读取。如果你使用了push,当前紧缩值被保存。如果你提供了一个n值,这个值将成为新的紧缩值。如果你指定了一个你选定的标示符,这个标示符将和新的紧缩值关联。

    每次出现有pop参数的pack编译指示从内部编译程序堆栈顶部取出一个值并将那个值作为新的紧缩对齐。如果你用了pop,而内部编译程序堆栈是空的,对齐值将从命令行得到,同时给出一个警告。如果你用了pop并指定了n的值,那个值将成为新的紧缩值。如果你用了pop并指定了一个标示符,将移去所有保存在堆栈中的的值直到匹配的找到匹配的标示符,和该标示符关联的紧缩值也被从堆栈中移出来成为新的紧缩值。如果没有找到匹配的标示符,将从命令行获取紧缩值并产生一个1级警告。默认的紧缩对齐是8。

    pack编译指示的新的增强功能允许你编写头文件保证在使用头文件之前和其后的紧缩值是一样的:

    /* File name: include1.h

    */

    #pragma pack( push, enter_include1 )

    /* Your include-file code ... */

    #pragma pack( pop, enter_include1 )

    /* End of include1.h */

    在前面的例子中,进入头文件时将当前紧缩值和标示符enter_include1关联并推入,被记住。在头文件尾部的pack编译选项移去所有在头文件中可能遇到的紧缩值并移去和enter_include1关联的紧缩值。这样头文件保证了在使用头文件之前和其后的紧缩值是一样的。

    新功能也允许你在你的代码内用pack编译指示为不同的代码,例如头文件设定不同的紧缩对齐。

    #pragma pack( push, before_include1 )

    #include "include1.h"

    #pragma pack( pop, before_include1 )

    在上一个例子中,你的代码受到保护,防止了在include.h中的任何紧缩值的改变。

    21  pointers_to_members
    C++特有

    #pragma pointers_to_members(pointer-declaration, [most-general-representation] )

    指定是否能够在相关类定义之前说明一个指向类成员的指针,并且用于控制指针的大小和解释指针的代码。你能够在你的源代码中使用pointers_to_members编译知识来代替/vmx编译程序选项。

    pointer-declaration参数指出是否在相关函数定义之前或其后你已经说明了一个指向成员的指针。pointer-declaration参数是下面两个符号之一:

    参数
     说明
     
    full_generality
     生成安全的,但是有时不能优化的代码。如果有一些指向成员的指针在相关类定义之前说明,你要用full_generality。这个参数总是使用由most-general-representation指定的指针表示方式。
     
    best_case
     对于所有指向成员的指针用最佳的表示方式生成安全的,优化的代码。需要在说明一个指向类成员指针之前定义类。默认是best_case。
     

    most-general-representaion参数指出在一个翻译单元中编译程序能够安全引用任何指向类成员指针的最小指针表示方式。这个参数可以是下列之一:

    参数
     说明
     
    single_inheritance
     最普通的表示方式是单继承,指向成员函数。如果用于指向具有多重或者虚拟继承方式类成员的指针,将产生一个错误。
     
    multi_inheritance
     最普通的表示方式是多重继承,指向成员函数。如果用于指向具有虚拟继承方式类成员的指针,将产生一个错误。
     
    virtual_inheritance
     最普通的表示方式是虚拟继承,指向成员函数。不会产生错误。当使用#pragma pointers_to_members (full_generality)时这是默认的参数。
     

    22  setlocale
    #pragma setlocale( "locale-string" )

    定义用于翻译宽字符常数和字符串文字量时用的地区(国家和语言)。由于用于从多字节字符转换到宽字符的算法根据地区或者由于在运行可执行程序不同的地方进行编译而不同,这个编译指示提供一种在编译时指定目标地区的方式。这保证宽字符字符串将以正确的格式保存。默认的locale-string是“C”。“C”地区将字符串中的每个字符作为wchar_t(即unsigned int)映射其值。

    23  vtordisp
    C++特有

    #pragma vtordisp({on | off} )

    允许隐藏的附加vtordisp构造函数/析构函数替换成员。vtordisp编译指示仅能够用于具有虚拟基类的代码。如果派生类从一个虚拟基类重载了一个虚拟函数,并且如果派生类的构造函数或析构函数用指向虚拟基类的指针调用了这个函数,编译程序将根据虚拟基类在类中引入一个附加的隐藏“vtordisp”域。

    vtodisp编译选项影响它后面的类布局。/vd0和/vd1选项为整个模块指定了相同的行为。指定off将禁止隐藏的vtordisp成员,指定on(默认)将在它们需要的时候允许vtordisp。仅在不可能出现类的构造函数和析构函数通过this指针调用其指向对象中的虚拟函数时才关闭vtordisp。

    #pragma vtordisp( off )

    class GetReal : virtual public { ... };

    #pragma vtordisp( on )

    24  warning
    #pragma warning( warning-specifier : warning-number-list [,warning-specifier : warning-number-list...] )

    #pragma warning( push[ , n ] )

    #pragma warning( pop )

    允许有选择地修改编译程序警告信息的行为。

    warning-specifier能够是下列值之一:

    warning-specifier
     含义
     
    on
    ce
     只显示指定信息一次。
     
    default
     对指定信息应用默认的编译程序选项。
     
    1,2,3,4
     对指定信息引用给定的警告等级。
     
    disable
     不显示指定信息。
     
    error
     对指定信息作为错误显示。
     

    warning-number_list能够包含任何警告编号。如下,在一个编译指示中可以指定多个选项:

    #pragma warning( disable : 4507 34; once : 4385; error : 164 )

    这等价于:

    #pragma warning( disable : 4507 34 )  // Disable warning messages

                                                //  4507 and 34.

    #pragma warning( once : 4385 )         // Issue warning 4385

                                                //  only once.

    #pragma warning( error : 164 )         // Report warning 164

                                                //  as an error.

    对于那些关于代码生成的,大于4699的警告标号,warning编译指示仅在函数定义外时有效。如果指定的警告编号大于4699并且用于函数内时被忽略。下面例子说明了用warning编译指示禁止、然后恢复有关代码生成警告信息的正确位置:

    int a;

    #pragma warning( disable : 4705 )

    void func()

    {

        a;

    }

    #pragma warning( default : 4705 )

    warning编译指示也支持下面语法:

    #pragma warning( push [ ,n ] )

    #pragma warning( pop )

    这里n表示警告等级(1到4)。

    warning(push)编译指示保存所有警告的当前警告状态。warning(push,n)保存所有警告的当前状态并将全局警告等级设置为n。

    warning(pop)弹出最后一次推入堆栈中的警告状态。任何在push和pop之间改变的警告状态将被取消。考虑下面的例子:

    #pragma warning( push )

    #pragma warning( disable : 4705 )

    #pragma warning( disable : 4706 )

    #pragma warning( disable : 4707 )

    // Some code

    #pragma warning( pop )

    在这些代码的结束,pop恢复了所有警告的状态(包括4705,4706和4707)到代码开始时候的样子。

    当你编写头文件时,你能用push和pop来保证任何用户修改的警告状态不会影响正常编译你的头文件。在头文件开始的地方使用push,在结束地方使用pop。例如,假定你有一个不能顺利在4级警告下编译的头文件,下面的代码改变警告等级到3,然后在头文件的结束时恢复到原来的警告等级。

    #pragma warning( push, 3 )

    // Declarations/ definitions

    #pragma warning( pop )

     三 编译选项的控制:

    编译选项对于一些工程非常有效,可以控制多语言版本,多种编译版本,多种编译方式等。

    选择菜单 Build->Configurations,增加一个工程配置,在Configuration中输入 Debug English 在 Copy Setting from 中选择 Debug 就可以(见下图),使用相同的方法,再增加一个 Debug Chinese 配置,并把原来的 Debug 删除。

    选择菜单 Project->Settings,在左边的 Setting For 中选择 Debug Chinese 在 Generatl 属性页的 Intermediate files 中输入 Debug Chinese,在 Output files 中输入 Chinese。在 Resource 属性页的 Resource file name 中输入 Debug Chinese/Example_Ch.res,(见下图)其它缺省就行

     

    四 注意一些问题

    #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方式的支持,这一特性应该基本稳定下来了。


    展开全文
  • 预编译预编译又称为预处理,是在编译之前做些代码文本的替换工作。JS代码 JS代码首先会被解析,也就是读取并转换成可用于编译的计算机索引的结构 然后再被编译成字节码 最后被编译成机器码,用于设备/浏览器执行 ...

    编译

    编译就是把高级语言变成计算机可以识别的2进制语言,计算机只认识1和0,编译程序把人们熟悉的语言换成2进制的。

    预编译

    预编译又称为预处理,是在编译之前做些代码文本的替换工作。

    JS代码


    • JS代码首先会被解析,也就是读取并转换成可用于编译的计算机索引的结构
    • 然后再被编译成字节码
    • 最后被编译成机器码,用于设备/浏览器执行

    在V8引擎中,解析和编译占JS执行时间的50%左右。

    展开全文
  • 预处理预编译

    2021-04-25 15:24:44
    处理器的主要作用就是把通过预处理的内建功能对一个资源进行等价替换,最常见的预处理有:文件包含,条件编译、布局控制和宏替换4种。 功能分类 指令 说明 文件包含 #include 引用其它的头文件 ...
  • 一,预编译 操作步骤:gcc -E hello.c -o hello.i 主要作用: 处理关于 “#” 的指令 【1】删除#define,展开所有宏定义。例#define portnumber 3333 【2】处理条件预编译 #if, #ifdef, #if, #elif,#endif 【3...
  • 1、预编译又称为预处理。如处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等。为编译做的预备工作的阶段。 2、编译(compilation , compile):编译阶段是检查语法,生成汇编...
  • 编译原理上机实验报告 预处理 预编译 字符串搜索
  • 预处理: C语言是建立在适当的关键字,表达式,语句以及使用它的规则上。然而 ,C标准不仅描述C语言,还描述如何执行 C 处理器,C标准库有那些函数,以及这些函数的工作原理。 C 处理器在程序执行之前检查...
  • C/C++ 预处理/预编译头文件

    千次阅读 2014-03-19 12:36:53
    处理器的主要作用就是把通过预处理的内建功能对一个资源进行等价替换,最常见的预处理有: 文件包含 条件编译 布局控制 宏替换 文件包含:#include是一种最为常见的预处理,主要是做为文件的引用组合源程序...
  • 在C语言的程序中可包括各种以符号#开头的编译指令,这些指令称为预处理命令。预处理命令属于C语言编译器,而不是C语言的组成部分。通过预处理命令可扩展C语言程序设计的环境。 一....预编译的主要...
  • 预处理 --》 编译 --》 运行,但步骤的不同是涉及到很多东西的,比如全局变量局部变量的赋值,为什么全局变量只能用常量来初始化而局部变量可以用带数学函数的表达式来初始化呢?如double pi = acos(-1.0); ...
  • 前言 如果你使用集成环境开发。那么你点击编译按钮就可...本文将以Linux下C语言的编译过程为例。对编译过程进行讨论。 编译一个C程序代码 下面以Linux环境下的test.c为例,test.c里的代码为: #include <stdio...
  • C语言的预处理和条件编译指令 预处理简介 C语言由源代码生成的各阶段如下: C源程序->编译预处理->编译->优化程序->汇编程序->链接程序->可执行文件 其中 编译预处理阶段,读取c源程序,...
  • 简单的jdbcTemplate预编译、回调等
  • 一、预处理预编译、编译预处理) 主要处理源代码文件中的以“#”开头的预编译指令 1.删除所有的#define,展开所有的宏定义。 2.处理所有的条件预编译指令,如“#if”、“#endif”、“#ifdef”、“#elif”“#else...
  • 编译预处理

    2020-09-27 15:09:23
    编译预处理是在编译源程序之前,由处理器对源程序进行加工处理工作,所谓处理器,是包含在编译器中的预处理程序。如图所示: 源程序的中的编译预处理命令一律以#开头,回车键结束,每条命令占一行,并且通常...
  • 编译预处理指令

    千次阅读 2020-02-27 12:32:06
    1.编译预处理指令 #开头的是编译预处理指令 它们不是C语言的成分,但是C语言程序离不开它们 #define用来定义一个宏 #define PI 3.14159//定义一个符号,这样定义出来的符号叫做一个宏,PI是这个宏的名字,而3,14159...
  • 预编译预处理的理解

    千次阅读 2014-04-10 16:04:27
    一、预编译头文件说明  所谓头文件预编译,就是把一个工程(Project)中使用的一些MFC标准头文件(如Windows.H、Afxwin.H)预先编译,以后该工程编译时,不再编译这部分头文件,仅仅使用预编译的结果。这样可以...
  • gcc中预编译、编译、汇编、链接   一、预编译 操作步骤:gcc -E test.c -o test.i 作用:处理关于 “#” 的指令 (1)删除#define,展开所有宏定义。例#define portnumber 3333 (2)处理条件预编译 #if, #ifdef, #...
  • 锲子 我们在各自的电脑上写下代码,得明白我们代码究竟是如何产生的,不想了解1,0什么的,但这几个环节必须掌握吧。 我们的代码会经过这4个环节,从而形成...预处理, 展开头文件/宏替换/去掉注释/条件编译 (t...
  • 预处理编译、汇编链接

    千次阅读 2020-03-30 17:00:00
    流程包括:预处理编译、汇编链接。hello.c文件为一个自己写好的包含main函数的c文件。 预处理 第一个阶段是预处理阶段,在正式的编译阶段之前进行。预处理阶段将根据已放置在文件中的预处理指令来修改源文件的...
  • C++中的预编译指令

    2020-12-22 16:25:34
    预处理过程读入源代码,检查包含预处理指令的语句宏定义,并对源代码进行响应的转换。预处理过程还会删除程序中的注释多余的空白字符。  预处理指令是以#号开头的代码行。#号必须是该行除了任何空白字符外的第...
  • C语言编译预处理

    2020-03-23 10:21:14
    文章目录一、预处理指令二、包含文件三、宏定义指令1、无参数的宏2、带参数的宏四、条件编译1、#ifdef2、#ifndef3、#undef五、课后...其中编译预处理阶段,读取C源程序,对其中的预处理指令(以#开头的指令)特殊...
  • 预处理编译

    2018-07-15 17:00:00
     预处理也称为预编译,它为编译做准备工作,主要进行代码文本的替换工作,用于处理#开头的指令,其中预处理产生编译器的输出。下表是一些常见的预处理指令及其功能。   经过预处理器处理的源程序与之前的源...
  • 流程: 预处理:展开头文件/宏替换/去掉注释/条件编译 (test.i main .i) 编译:检查语法,生成汇编 (test.s main .s) 汇编:汇编代码转换机器码 ...
  • 预处理编译阶段

    2019-07-18 18:59:02
    其中编译预处理阶段,读取c源程序,对其中的伪指令(以#开头的指令)特殊符号进行处理。或者说是扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器。预处理过程先于编译器对源代码进行处理。 在C ...
  • 预处理预编译(C++)

    2014-05-21 14:41:13
    # 预处理预编译(C++) 一、预处理的由来:  在C++的历史发展中,有很多的语言特征(特别是语言的晦涩之处)来自于C语言,预处理就是其中的一个。C++从C语言那里把C语言预处理器(被Bjarne博士简称为Cpp,不...
  • 第6章 函数与编译预处理 一选择题 1C 2A 3A 4D 5A 6A 7C 8B 9B 10C 11B 12B 13A 14D 15C 16C 17C 18C 19A 20D 21B 22B 23C 24A 25C 26D 27C 28D 二写出下列程序的运行结果 17 212 39 4817 55 6 688 73 6 9 12 810 97...
  • 锲子 我们在各自的电脑上写下代码,得明白我们代码究竟是如何产生的,不想了解1,0什么的,但这几个环节必须掌握吧。 我们的代码会经过这4个环节,从而形成...预处理, 展开头文件/宏替换/去掉注释/条件编译 (t...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 50,020
精华内容 20,008
关键字:

预处理和预编译