基本类型库头文件

 

基本类型库头文件由七个部分组成:

1. 头部固定正文:由注释、COMDEF.H(定义用在头部的一些标准宏)的#include语句和其它繁杂的安装信息组成。

2.前向引用和类型定义:由象struct IMyinterface之类的结构说明和用于一些TKIND_ALIAS项的类型定义组成。

3.灵敏指针说明:模块类_com_ptr_t是一个封装接口指针和消除调用AddRef、Release 和QueryInterface函数需求的灵敏指针实现。此外,它隐藏了创建一个新COM对象中的CoCreateInstance调用。此部分采用宏语句_COM_SMARTPTR_TYPEDEF将COM接口的类型定义创建为_com_ptr_t模板类的模板特例化。例如,对于界面IFoo,.TLH文件包含有:

_COM_SMARTPTR_TYPEDEF(IFoo,_ _uuidof(IFoo));

编译器将其扩展为:type def _com_ptr_t<_com_IIID<IFoo,_ _uuidof(IFoo) >> IFooPtr;

类型IFooPtr可以用在原始的界面指针IFoo*的地方。结果,就不需调用各种IUnknown成员函数。

4. 类型信息(typeinfo)说明:主要由类定义和其它项组成,这些项说明由ITyptLib:GetTypeInfo返回的单个的信息类型项目。在这部分,每个来自于类型库的信息类型都以一种依赖于TYPEKIND信息的格式反映在该头部。

5. 任选旧式GUID定义:包含命名的GUID常量的初始化过程,这些定义是格式CLSID_CoClass和IID_Interface的名称,与那些由MIDL编译器产生的类似。

6. 用于第二个类型库头部的#include语句。

7. 结尾固定正文:目前包括#pragma pack(pop)。

以上这些部分除头部固定正文和结尾固定正文部分之外,都被包括在原来的IDL文件中以library语句指定其名称的名称空间中。你可以通过用名称空间显式限定或包括如下语句从类型库头部使用该名称。

using namespace MyLib

在源代码的#import语句之后立即

名称空间可用#import指令的no_namespace属性来阻止。但阻止的名称空间可能导致名称冲突。名称空间也可用rename_namespace属性重新换名。

编译器提供完全路径给需要依赖当前正在处理的类型库的任何类型库。路径以注释格式写入到由编译器为每个处理的类型库生成的类型库头部(.TLH)。

如果一个类型库包含了对其它类型库定义的类型引用,.TLH文件将包括以下注释:

//

//Cross-referenced type libraries:

//

//#import "c:/path/typelib0.tlb"

//

在#import注释中的实际文件名是存储在寄存器中交叉引用的类型库全路径。如果你遇到由于省略类型定义的错误时,检查.TLH头部的注释,看哪一种依赖类型库需要先输入。在编译该.TLI文件时可能的错误有语法错误(例如C2143,C2146,C2321)、C2501(缺少说明指示符)或C2433(在数据说明中禁止′inline′)。

你必须确定哪些依赖注释是不被系统头部给出的,而是在依赖类型库的#import指令前的某处给出一个#import指令以消除这些错误。

exclude属性exclude(“称1”[,“名称2”,...])

名称1

被排斥的第一个项

名称2

被排斥的第二个项(如有必要)

类型库可能包含在系统头部或其它类型库内定义的项的定义。该属性可用于从生成的类型库头文件中排斥这些项。这个属性可带任意数目的参量,每个参量是一个被排斥的高级类型库项目:

high_method_prefix属性

high_method_prefix("Prefix")

Prefix

被使用的前缀

在缺省的情况下,高级错误处理属性和方法用一个无前缀命名的成员函数来展示。这个名称来自于类型库。high_method_prefix属性说明一个前缀以用于命名这些高级属性和方法。

high_property_prefixes属性

high_property_prefixes("GetPrefix,""PutPrefix,""PutRefPrefix")

GetPrefix

用于propget方法的前缀

PutPrefix

用于propput方法的前缀

PutRefPrefix

用于propputref方法的前缀

在缺省情况下,高级错误处理方法,如propget、propput和propputref,分别采用以前缀Get、Put和PutRef命名的成员函数来说明。high_property_prefixes属性用于分别说明这三种属性方法的前缀。

implementation_only属性

implementation_only属性禁止.TLH头文件(基本头文件)的生成。这个文件包括了所有用于展示类型库内容的说明。该.TLI头文件和wrapper成员函数的实现,将被生成且包含在编译过程中。

当指定该属性时,该.TLI头部的内容将和用于存放普通.TLH头部的内容放在相同的名称空间。此外,该成员函数不会作为联编说明。implementation_only属性一般希望与no_implementation属性配对使用,以跟踪预编译头文件(PCH)之外的实现。一个有no_implementation属性的#import语句被置于用来创建pch的源区域中,结果PCH将被一些源文件所用。一个带implementation_only属性的#import语句随后被用在PCH区域之外。在一个源文件里只需用一次这种语句。这将生成不需对每个源文件进行额外重编译的所有必要的wrapper成员函数。

注意:一个#import语句中的implementation_only属性必须和相同类型库中no_implementation属性的另一个#import语句配套使用。否则,将产生编译错误。这是因为带no_implementation属性的#import语句生成的wrapper类定义需要编译implementation_only属性生成的语句实现。

include(...)属性

Include(名称1[,名称2,...])

名称1

第一个被强制包含的项

名称2

第二个被强制包含的项(如果必要)

类型库可能包含在系统头部或其它类型库中定义的项的定义。#import指令试图用自动排斥这些项来避免多重定义错误。若这些项已经被排斥,象警告C4192所指出的那样,且它们不应该被排斥,则这个属性可用于禁止自动排斥。该属性可带任意数目的参量,每个参量应是被包括的类型库项的名称。

inject_statement属性

inject_statement("source_text")

source_text

被插入到类型库头文件的源文本。

inject_statement属性将其参量作为源文本插入类型库头部。此文本被置于包括头文件中类型库内容的名称空间说明的起始处。

named_guids属性

named_guids属性让编译器定义和初始化模板LIBID_MyLib、CLSID_MyCoClass、IID_MyInterface和DIID_MyDispInterface的旧式格式的GUID变量。

no_implementation属性

该属性阻止.TLI头文件的生成,这个文件包含wrapper成员函数的实现。如果指定这个属性,则展示类型库项说明的.TLH头将生成没有一个#include语句包括该.TLI头文件。

该属性与implementation_only属性配套使用。

no_auto_exclude属性

类型库可能包括在系统头部或其它类型库中定义的项的定义。#import试图通过自动排斥这些项来避免多重定义错误。当这样做时,每个被排斥的项都将生成一个C4192警告信息。你可禁止这个属性使用自动排斥。

no_namespace属性

#import头文件中的类型库内容一般定义在一个名称空间里。名称空间的名称在原来IDL文件的library语句中指定。如果指定no_namespace属性,编译器就不会生成这个名称空间。

如果你想使用一个不同的名称空间,应代替使用rename_namespace属性。

raw_dispinterfaces属性

raw_dispinterfaces属性让编译器生成一个低级wrapper函数。该函数用于调用IDispatch::Invoke和返回HRESULT错误代码的dispinterface方法和属性。如果未指定此属性,则只生成高级wrapper,它在失败时丢弃该C++异常。

raw_interfaces_only属性

raw_interfaces_only属性禁止生成错误处理wrapper函数以及使用这些wrapper函数的_ _declspec(属性)说明。

raw_interfaces_only属性也导致删除在命名non__property函数中的缺省前缀。通常该前缀是raw_。若指定此属性,函数名称将直接从类型库中生成。该属性只允许展示类型库的低级内容。

raw_method_prefix属性

raw_method_prefix("Prefix")

Prefix

被使用的前缀

用raw_作为缺省前缀的成员函数展示低层属性和方法,以避免与高级错误处理成员函数的名称冲突。raw_method_prefix属性用于指定一个不同的前缀。注意: raw_method_prefix属性的效果不会因raw_method_prefix属性的存在而改变。在说明一个前缀时,raw_method_prefix总是优先于raw_interfaces_only。若两种属性用在同一个#import语句中时,则采用raw_method_prefix指定的前缀。

raw_native_types属性

在缺省情况下,高级错误处理方法在BSTR和VARIANT数据类型和原始COM界面指针的地方使用COM支持类_bctr_t和_variant_t。这些类封装了分配和取消分配这些数据类型的存储器存储的细节,并且极大地简化了类型造型和转换操作。raw_native_types属性在高级wrapper函数中禁止使用这些COM支持类,并强制替换使用低级数据类型。

raw_property_prefix属性

raw_property_prefix("GetPrefix","PutPrefix","PutRefPrefix")

GetPrefix

用于propget方法的前缀

PutPrefix

用于propput方法的前缀

PutRefPrefix

用于propputref方法的前缀

在缺省情况下,低级方法propget、propput和propputref分别用后缀为get_、put_和putref_的成员函数来展示。这些前缀与MIDL生成的头文件中的名称是兼容的。raw_property_prefixes属性分别用于说明这三个属性方法的前缀。

rename属性

rename("OldName,""NewName")

OldName

类型库中的旧名

NewName

用于替换旧名的名称

rename属性用于解决名称冲突的问题。若该属性被指定,编译器将在类型库中的OldName的所有出现处用结果头文件中用户提供的NewName替换。

此属性用于类型库中的一个名称和系统头文件中的宏定义重合时。若这种情况未被解决,则将产生大量语法错误,如C2059和C2061。

注意:这种替换用于类型库的名称,而不是用于结果头文件中的名称。

这里有一个例子:假设类型库中有一个名称为MyParent的属性,且头文件中定义了一个用在#import之前的宏GetMyParent。由于GetMyParent是用于错误处理属性get的一个wrapper函数的缺省名称,所以将产生一个名称冲突。为解决这个问题,使用#import语句中的以下属性:

rename("MyParent","MyParentX")

该语句将重新命名类型库中的名称MyParent,而试图重新命名GetMyParentwrapper名称将会出错:

rename("GetMyParent","GetMyParentX")

这是因为名称GetMyParent只出现在结果类型库头文件中。

rename_namespace属性

rename_namespace("NewName")

NewName

名称空间的新名称

rename_namespace属性用于重新命名包含类型库内容的名称空间。它带有一个指定名称空间新名newname的参量。

消除名称空间可以使用no_namespace属性。

C++特殊处结束

#include指令

#include指令告诉预处理器处理一个指定文件的内容,就象这些内容以前就在这条指令出现的源程序中。你可以把常量和宏定义放在包含文件中,然后用#include指令把这些定义加到任何源文件中。包含文件对于外部变量和复杂数据类型结合的说明也是有用的。

你只需在为此目的创建的一个包含文件中定义和命名这些类型一次。

语法

#include "path-spec"

#include

path_spec是一个前面有目录说明的任选文件名。这个文件名必须命名一个现存文件。

path_spec的语法依赖于编译该程序的操作系统。

这两种语法格式都导致用已说明的包含文件的全部内容来替换该指令。两种格式的区别在于路径未完整指定时预处理器搜索头文件的顺序。

语法格式 动作

引号格式 这种格式指示预处理器先在包含#include语句的文件的相同目录内搜索,然后在任何包括该文件的目录中搜索。随后预处理器沿着/I编译器选项指定的路径搜索,最后是在INCLUDE环境变量说明的路径搜索

尖括号格式 这种格式指示预处理器首先在/I编译器选项指定的路径中搜索包含文件。然后在INCLUDE环境变量说明的路径中搜索

一旦预处理器找到指定文件,它就立即停止搜索。如果用双引号给出一个明确完整的包含文件的路径,预处理器将只搜索该路径规格而忽略标准目录。

如果在双引号间的文件名不是一个完整的路径规格,预处理器将先搜索“父”文件的目录。父文件是一个包含#include指令的文件。例如,如果你把名称为file2的文件包括在一个名称为file1的文件中,file1就是父文件。

包含文件可被嵌套;这指的是一个#include指令出现在以另一个#include指令命名的文件里。例如,以上的文件file2,可包含文件file3,在这种情况下,file1是file2的父文件,而且是file3的祖父文件。

当包含文件嵌套时,目录搜索首先由父文件的目录开始,然后,搜索祖父文件的目录。

因此,搜索从包含当前处理源文件的目录开始,若文件未找到,搜索就转到/I编译器选项指定的目录,最后搜索include环境变量指定的目录。

下面的例子给出使用尖括号的文件包括:

#include

这个例子把名称为STDIO.H的文件内容加入到源程序中。尖括号指示预处理器在搜索完/I编译器选项说明的目录之后,搜索STDIO.H的环境变量指定的目录。下面的例子给出用引号格式的文件包括:#include "defs.h"

这个例子把DEFS.H指定的文件内容加入源程序。双引号标记意味着预处理器首先搜索包含父源文件的目录。

包含文件的嵌套可高达10层,只要在处理嵌套的#include指令时,预处理器就会不断地把包含文件加入到最初的源文件中。

Microsoft特殊处

为了定位可包括源文件,预处理器首先搜索/I编译器选项指定的目录。若/I选项未给定或已失败,预处理器就用INCLUDE环境变量搜索尖括号内的包含文件。INCLUDE环境变量和/I编译器选项可包含用分号分开的多个路径。若在/I选项的部分或在INCLUDE环境变量里有多于一个的目录,预处理器将以它们出现的顺序对它们进行搜索。

例如,命令:

CL /ID:/MSVC/INCLUDE MYPROG.C

导致预处理器在目录D:/MSVC/INCLUDE中搜索诸如STDIO.H的包含文件。命令:SET INCLUDE=D:/MSVC/INCLUDE

CL MYPROG.C

有相同的作用。如果所有搜索都失败了,将产生一个致命编译错误。

如果用包括一个冒号的路径(例如,F:/MSVC/SPECIAL/INCL/TEST.H)来完整地说明一个包含文件的文件名,预处理器将沿此路径搜索。

对于指定为#include "path_spec"的包含文件,目录搜索将从父文件的目录开始,然后搜索祖父文件的目录。因此,搜索将从包含当前处理的#include指令的源文件的目录开始,如果没有祖父文件或文件未找到,搜索将继续,就像文件名包括在尖括号中一样。

Microsoft特殊处结束

#line指令

#line指令告诉预处理器将编译器内部存储的行号和文件名转变为一个给定的行号和文件名。编译器使用该行号和文件名指出编译过程中发现的错误。行号一般指的是当前输入行,文件名指当前输入文件。每处理一行,行号就增1。

语法

#line

数字序列 “文件名”opt

数字序列的值可以是任何整型常数。宏替换可在预处理语言符号中执行,但结果必须求值为正确的语法。文件名可以是任意字符的组合,且应括在双引号(“”)间。如果省略文件名,则前面的文件名保持不变。

你可以通过编写一个#line指令来改动源行号和文件名。翻译器使用行号和文件名来确定预定义宏__FILE_ _和_ _LINE_ _的值。你可以使用这些宏把自描述错误消息加入到程序文本中。有关这些宏的更多信息参见预定义的宏。

__FILE_ _宏扩展成内容为用双引号(“”)括起的文件名的一个字符串。

如果你改变行号和文件名,编译器将忽略原有的值,用新值继续处理。#line指令通常被程序生成器用来生成指向最初源程序的错误消息,而不是生成程序。下面的例子用于说明#line以及_ _LINE_ _和_ _FILE_ _宏。在这个语句中,内部存储的行号设置为151,文件名改为copy.c。

#line 151 "copy.c"

在这个例子中,若一个给定的“断言”(assertion)不为真,则宏ASSERT使用预定义宏__LINE_ _和_ _FILE_ _打印出一个关于源文件的错误消息。

#define ASSERT(cond)

if( !(cond) ) /

{ printf("assertion error line %d, file(%s)/n",/

__LINE_ _,_ _FILE_ _); }

Null指令

空预处理器指令是一行中一个单独的数字标号(#),无任何作用。

语法

#

#undef指令

正如其名所隐含的,#undef指令取消(反定义)一个原来由#define指令创建的名称。

语法

#undef

标识符

#undef指令取消标识符的当前定义。其结果是,标识符的每次出现都将被预处理器所忽略。为取消一个用#undef的宏定义,只须给出宏的标识符,不须给出参数表。

你也可以将#undef指令用于一个原来未定义的标识符。这将确认这个标识符是未定义的。宏替换不能在#undef语句中执行。

#undef指令通常和一个#define指令匹配,以在源程序中创建一个区域,在这个区域中一个标识符有其特定的含义。例如,源程序的一个特有函数可以使用显式常量定义不影响程序余下部分的环境特定值。#undef指令也可与#if指令配对以控制源程序的条件编译过程。有关更多信息参见“#if、#elif、#else和#endif指令”。

下面的例子中,#undef指令取消了一个符号常量和一个宏的定义,注意该指令只给出了宏的标识符。

#define WIDTH 80

#define ADD(X,Y) (X)+(Y)

...#undef WIDTH

#undef ADD

Microsoft特殊处

宏可通过采用/U选项的命令行反定义,此命令行后跟反定义的宏名称。此命令与在文件开头处的#undef 宏名称语句序列的作用是相等的。

Microsoft特殊处结束


 

预处理器操作符

#define指令的文本中有四种预处理器特有的操作符(它们的总结参见下面的表)。

字符化、字符串化和语言符号粘贴操作符将在下面三章中讨论。defined操作符的信息参见“#if、#elif、#else和#endif指令”。

运算符 动作

字符串化操作符(#) 将相应实参置于双引号内

字符化操作符(#@) 将相应的参量置于单引号内,且将其作为字符处理(Microsoft特殊处)

语言符号粘贴操作符(##) 可将语言符号作为实参使用,且将其合并为其它 的语言符号

续表

定义的操作符 简化在某特定宏指令中复合表达式的写法

字符串化操作符(#)

数字符号或“字符串化”操作符(#)将宏参数(扩展后)转化为字符串常量。它只用于带参量的宏。如果它在宏定义中的一个形式参量之前,宏调用传给的实际参量就被括在双括号中,且被看作为一个字符串文字。然后该字符串文字将替换该宏定义中操作符和形参组合的每次出现。

实参的第一个语言符号之前和最后一个语言符号之后的空白被忽略。实参中语言符号之间的所有空白在结果字符串语义中都被看作为一个空格。因此,若实参中的一个注解出现在两个语言符号之间,它将被看作为一个空格。结果字符串文字自动地与任何仅用空格分开的相邻字符串文字连接。

此外,如果一个包含在参量里的字符在用作一个字符串文字(例如,双引号(")或反斜杠(/)字符)时通常需要一个转义序列,必要的转义反斜杠被自动地插入字符之前。下面的例子给出了一个包含字符串化操作符的宏定义和一个调用该宏的main函数:

#define stringer(x) printf(#x "/n")
void main( )
{
   stringer(In quotes in the printf function call/n);
   stringer("In quotes when printed to the screen"/n);
stringer("This:/" prints an escaped double quote");
}

这种调用在预处理时会被扩展,产生如下代码:

void main()
{
   printf("In quotes in the printf function call/n" "/n");
   printf("/"In quotes when printed to the screen/"/n" "/n");
   printf("/"This; ///" prints an escaped double quote /"" "/n");
}

当运行该程序时,每行的屏幕输出如下:

In quotes in the printf function call

"In quotes when printed to the screen"

"This; /" prints an escaped double quotation mark"

Microsoft特殊处

Microsoft C(版本6.0及更早版本)扩展ANSI C的标准,ANSI C扩展在字符串文字和字符常量中出现的宏形式参量不再被支持。依赖于此扩展的代码应该使用字符串化操作符(#)重写。

Microsoft特殊处结束

字符化操作符(#@)

Microsoft特殊处

字符化操作符只可用于宏参量,若宏定义中#@在一个形参前,则实参应被放在单引号中,在宏扩展时作为一个字符处理。例如:

#define makechar(x) #@x

将语句:

a=makechar(b);

扩展为:

a='b';

单引号字符不能用于字符化操作符。

Microsoft特殊处结束语

言符号粘贴操作符(##)

双数字语言符号或“语言符号粘贴”操作符(##),有时称作“合并”操作符,用于类对象宏和类函数宏中。它允许将分开的语言符号加入一个单个语言符号中,因此不能是宏定义的第一个语言符号或最后一个语言符号。

如果一个宏定义中的形参在语言符号粘贴操作符的前后,则形参将立即被未扩展的实参替换。在替换之前不对参量执行宏扩展。

然后,语言符号字符串中语言符号粘贴操作符的每次出现将被删除,其前后的语言符号将被合并。其结果语言符号必须是一个有效的语言符号。若其有效,如果该语言符号代表一个宏名称,则扫描它以发现可能的替换。该标识符表示在替换前程序中己知合并的语言符号的名称。每个语言符号都代表一个在程序中或在编译器命令行中定义的语言符号。

该操作符前后的空白是任意的。

如下例子说明了程序输出中字符串化操作符和语言符号粘贴操作符的用法:#define paster(n) printf("token" #n "=%d",taken##n)

int token9=9;

若一个宏用一个类似于下面的数值参量调用:

paster(9);

宏将生成:

printf("token" "9" "=%d",token9);

它变成为:

printf("token9 = %d", token9 );


 

对宏扩展的预处理在所有那些不是预处理指令的行(第一个非空白字符不是#的行),以及其指令并未作为条件编译的一部分而忽略的行中进行。“条件编译”指令允许通过检测一个常量表达式或标识符以决定在预处理过程中哪个文本块送入编译器、哪个文本块从源文件中删除,并以此种方式控制一个源文件中某部分的编译。

#define指令通常使用有意义的标识符与常量、关键字、常用语句和表达式关联。表示常量的标识符有时被称作“符号常量”或“显式”常量。表示语句或表达式的常量称为“宏”。在本预处理器文档中,只使用术语“宏”。

当宏的名称在程序源文本或在某些其它预处理器命令的参量中被识别时,它被处理为对该宏的调用。宏名称被宏体的一个拷贝所替换。若该宏接受参量,宏名称后的实参就会替换宏体中的形参。用宏体中处理的拷贝来替换一个宏调用的过程,称为宏调用的“扩展”。

实际的术语中有两种类型的宏。“类对象”宏不带参量,而“类函数”宏可定义为带参量。因此它们的形式和功能都象函数调用,由于宏不生成实际的函数调用,所以有时可用宏替代函数调用使程序运行得更快,(在C++中,inline函数通常是一个好方法),然而,如果不小心的定义和使用宏,也可能造成麻烦。在带参量的宏定义时,你必须使用括号以保持一个表达式中正常的优先级,同时宏也不能正确地处理具有副作用的表达式。有关更多的信息参见“#define指令”中的例子getrandom。

一旦你定义了一个宏,你不能不经取消该宏原有定义,而重新定义它为一个不同的值。但可用正好相同的定义来重定义该宏,因此,一个程序中宏的相同定义可出现多次。

#undef指令用于取消宏的定义。一旦取消该宏的定义,就可重新定义该宏为一个不同的值。#define和#undef两节分别详细讨论了#define和#undef指令。

宏和C++

C++提供了一些新的功能。其中有些功能替代了原来由ANSI C所提供的功能。这些新的功能增强了类型安全性和该语言的可预测性:

* 在C++中,以const说明的对象可用于常量表达式中,这使程序说明有类型和值信息的常量,以及能被调试器逐个字符检查的枚举值的常量。使用预处理器指令#define定义常量并不精确。除非在程序中找到一个带地址的表达式,否则一个const对象将不分配任何存储。

* C++联编函数替代了函数类型宏,相对于宏来说使用联编函数的优势在于:

* 类型安全性。联编函数和一般函数一样需进行相同的类型检测,宏无类型安全性检测。

* 纠正具有副作用的参量处理。联编函数在进入函数体之前对参量的表达式求值。因此,一个有副作用的表达式将是安全的。

对于联编函数的更多信息参见inline、_ _inline节。为了向下兼容,Microsoft C++保留了所有在ANSI C和更早C++规格中的预处理器功能。

预定义宏

编译器可识别六种预定义的ANSI C宏(参见表1.1),而Microsoft C++实现提供更多的预定义宏(参见表1.2)。这些宏不带参量,但不能被重定义。它们的值(除__LINE_ _和_ _FILE_ _外)必须是经过编译的常量。下面列出的一些预定义宏须用多个值来定义,它们的值可在Visual C++开发环境中选择相应的菜单选项来设置或采用命令行开关。更多的信息参见下表。

表1.1 ANSI 预定义宏

说明
__DATE_ _当前源文件的编译日期。日期是格式为Mmm dd yyyy的字符串文字。月份名称Mmm与在TIME.H中说明的库函数asctime产生的日期一样
__FILE_ _当前源文件名称。__FILE_ _扩展为用双引号括起的一个字符串
__LINE_ _当前源文件的行号。该行号是一个十进制整型常量。可用一个#line指令修改
__STDC_ _指出与ANSI C标准的完全一致性。仅当给出/Za编译器选项且不编译C++代码时定义为整型量1;否则是不确定的
__TIME_ _当前文件的最近编译时间。该时间是格式为hh:mm:ss的字符串文字
__TIMESTAMP_ _当前源文件的最近修改日期。日期是格式为Ddd Mmm Datehh:mm:ss yyyy的字符串文字,这里Ddd是星期几的简写,Date是从1到31的一个整数表

表1.2 Microsoft特殊预定义的宏

说明
__CHAR_UNSIGNED缺省char类型是无符号的,当指定/J时定义的
__cplusplus仅为C++程序定义
__CPPRTTI定义为用/GR编译的代码(允许运行时类型信息)
__CPPUNWIND定义为用/GX编译的代码(允许异常处理)
__DLL指定/MD或/MDd(多线程DLL)时定义的
__M_ALPHA为DEC ALPHA平台定义,使用ALPHA编译器时定义为1,若使用另一个编译器时不定义
__M_IX86为x86处理器定义,参见表1.3
__M_MPPC为Power Macintosh平台定义,缺省为601(/QP601)参见表1.4
__M_MRX000为MIPS平台定义,缺省为4000(/QMR4000),参见表1.5
__M_PPC为PowerPC平台定义,缺省为604(/QP604),参见表1.6__MFC_VER为MFC版本定义,为Microsoft Founndation类库4.21定义为0x0421,它总是定义的
__MSC_EXTENSIONS该宏在使用/Ze编译选项(缺省值)时定义,定义时其值总为1
__MSC_VER定义编译器版本,对于Microsoft Visual C++ 6.0定义为1200,它总是定义的
__MT当指定/MD或/MDd(多线程DLL)或/MT或/MTd(多线程)选项时定义
__WIN32为Win32应用程序而定义。它总是定义的

如下表所示,编译器对反映处理器选项的预处理器标识符产生一个值。

表1.3 _M_IX86的值

开发者的选项命令行选项返回值
Blend/GB_M_IX86=500(缺省值。将来的编译器将给出一个不同的值以影响主处理器)
Pentium/G5_M_IX86=500
Pentiumpro/G6_M_IX86=600
80386/G3_M_IX86=300
80486/G4_M_IX86=400

表1.4 _M_MPPC的值

开发者的选项命令行选项返回值
PowerPC 601/QP601_M_MPPC=601(缺省值)
PowerPC 603/QP603_M_MPPC=603
PowerPC 604/QP604_M_MPPC=604
PowerPC 620/QP620_M_MPPC=620

表1.5 _M_MRX000的值

开发者选项命令行选项返回值
R4000/QMR4000_M_MRX000=4000(缺省值)
R4100/QMR4100_M_MRX000=4100
R4200/QMR4200_M_MRX000=4200
R4400/QMR4400_M_MRX000=4400
R4600/QMR4600_M_MRX000=4600
R10000/QMR10000_M_MRX000=10000

表1.6 _M_PPC的值

开发者选项命令行选项返回值
R4000/QMR4000_M_MRX000=4000(缺省值)
R4100/QMR4100_M_MRX000=4100
R4200/QMR4200_M_MRX000=4200
R4400/QMR4400_M_MRX000=4400
R4600/QMR4600_M_MRX000=4600
R10000/QMR10000_M_MRX000=10000
### 关于头文件的使用方法 在C++编程中,头文件的作用是声明中的函数、类和其他资源以便程序能够访问并使用这些预定义的功能。以下是有关头文件的具体使用方法以及示例。 #### 头文件的概念 头文件通常是`.h`或`.hpp`扩展名的文件,它包含了的接口部分,比如函数原型、宏定义、类型定义等。通过包含头文件,程序员可以在自己的代码中调用所提供的功能[^1]。 #### 静态与动态的区别 - **静态**:通常以`.lib`(Windows)或`.a`(Linux/Unix)形式存在,在编译阶段会被链接到目标程序中,最终生成一个完全独立的可执行文件。 - **动态**:如`.dll`(Windows)或`.so`(Linux),不会直接嵌入到最终的应用程序里,而是运行时加载。这种方式减少了内存占用和磁盘空间需求[^2]。 #### 如何使用及其对应的头文件? 要利用某个外部,一般需要完成以下几个操作: 1. **包含必要的头文件** 在源码顶部加入适当的include指令来引入所需的头文件。例如: ```cpp #include "mylibrary.h" ``` 2. **配置项目设置** 如果使用的IDE环境像Visual Studio,则可能还需要调整项目的属性页,指定额外的包含目录(Include Directories)和目录(Library Directories)。对于VS2019来说,如果采用的是#pragma方式自动导入LIB文件,那么可以直接这样写: ```cpp #pragma comment(lib, "mylibrary.lib") ``` 这样做可以让编译器知道去哪里寻找实际的实现代码[^3]。 3. **链接正确的版本** - 对于静态而言,只需确保正确指定了`.lib`的位置即可; - 而针对DLL之类的动态情况稍复杂些,除了上述步骤外还需考虑导出符号表等问题,并且部署应用时记得随附相应DLL副本给用户。 4. **实例化对象或者调用成员函数** 假设MyClass是从所选里继承来的模板类别型参数T的一个具体表现形式如下所示: ```cpp MyClass<int> myObject; int result = myObject.doSomething(); ``` 以上就是基本流程概述加上简单的例子展示如何运用第三方提供的及相关联的头部文档资料来进行开发工作了!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值