首页 > 技术文章 > 独立看第一个C++程序到最终结果log----2019-04-15

MCSFX 2019-04-15 19:25 原文

本文纯为本人记录,有网上诸多参考,请勿转发! 记录可能可能有点啰嗦,自己划重点吧!!

(无论是生活还是工作,如果很困惑,千万不要消极一定要勇敢积极的面对它,不用说太多懂得人自然懂,一定要解决这个疑惑就多读书吧! 书是你最好的交流对象 ---2019-04-15)

 

参考:

1.c/c++ int _tmain(int argc, _TCHAR* argv[]) : https://blog.csdn.net/exceptional_czr/article/details/38786707

2.CoInitialize()与COM : https://blog.csdn.net/chenglingsu6/article/details/5999134

3.tlb、tlh和tli文件的关系 :https://www.cnblogs.com/taoxu0903/archive/2008/06/09/1216390.html

4.关于C++中的__uuidof :https://blog.csdn.net/qq_37354286/article/details/82292437

5.C++中Cstring使用小结 : https://www.cnblogs.com/welfare/articles/300867.html

6.c++中LPCTSTR,LPTSTR 解释: https://blog.csdn.net/u011555996/article/details/87350693

7.c++中__declspec用法总结 :https://blog.csdn.net/hollyhock13/article/details/2776276

 

 

 

 

解释:

1.c/c++ int _tmain(int argc, _TCHAR* argv[]);   

main()是标准C++的函数入口。标准C++的程序入口点函数,默认字符编码格式ANSI 函数签名为: int main(); int main(int argc, char* argv[]);
_tmain()是微软操作系统(windows)提供的对unicode字符集和ANSI字符集进行自动转换用的程序入口点函数。 函数签名为: int _tmain(int argc, TCHAR *argv[]) 当你程序当前的字符集为unicode时,int _tmain(int argc, TCHAR *argv[])会被翻译成 int wmain(int argc, wchar_t *argv[]) 当你程序当前的字符集为ANSI时,int _tmain(int argc, TCHAR *argv[])会被翻译成 int main(int argc, char *argv[])

1. Main是所有c或c++的程序执行的起点,_tmain是main为了支持unicode所使用的main的别名。_tmain()不过是unicode版本的的main().

  2. _tmain需要一个返回值,而main默认为void.

  3. _tmain的定义在<tchar.h>可以找到,如#define _tmain main,所以要加#include <tchar.h>才能用。_tmain()是个宏,如果是UNICODE则他是wmain()否则他是main().

  4. (一般_t、_T、T()这些东西都是宏都和unicode有关系),对于使用非unicode字符集的工程来说,实际上和main没有差别(其实就算是使用unicode字符集也未必有多大的差别)。

  5. 因此_tmain compile后仍为main,所以都可以执行.

  main()是WINDOWS的控制台程序(32BIT)或DOS程序(16BIT).

  WinMain()是WINDOWS的GUI程序.

    wmain也是main的另一个别名,是为了支持二个字节的语言环境

  -----------------------

  int main( int argc[ , char *argv[ ] [, char *envp[ ] ] ] );

  wmain( int argc, wchar_t *argv[ ], wchar_t *envp[ ] )

  int _tmain(int argc, _TCHAR* argv[])

 

2.CoInitialize()与COM:

Coinitialize  参数为保留参数,必须为NULL

CoInitialize是 Windows提供的API函数,用来告诉 Windows以单线程的方式创建com对象。应用程序调用com库函数(除CoGetMalloc和内存分配函数)之前必须初始化com库。  

返回值S_OK : 该线程中COM库初始化成功S_FALSE 该线程中COM库已经被初始化 CoInitialize () 标明以单线程方式创建。  使用 CoInitialize 创建可以使对象直接与线程连接,得到最高的性能。  

CoInitialize并不装载COM 库,它只用来初始化当前线程使用什么样的套间。使用这个函数后,线程就和一个套间建立了对应关系。线程的套间模式决定了该线程如何调用COM对象,是否需要列集等。  

CoInitialize ()并不会干扰客户和服务器之间的通信,它所做的事情是让线程注册一个套间,而线程运行过程中必然在此套间。   CoInitialize和CoUninitialize必须成对使用

在每个线程函数里,如果要使用COM对象就需要调用CoInitialize或CoInitializeEX 在线程退出的时候释放. 当然如果你的线程不需要COM对象,就没必调用.

COM(ComponentObjectModel,组件对象模型) 在Windows操作平台下,众多以COM形式提供的组件模块,如DirectX多媒体软件包、OLEDB/ADO数据库组件系统等,极大地丰富了操作系统的功能。由于COM机制允许任意两组件之间相互通信而不必关心是在何种计算机上的何种操作系统下运行,也不用关心组件是使用何种语言编制的,这使COM技术拥有了强大的生命力。尤其是Windows2000同COM的下一代产品COM+的结合更加紧密,将使COM/COM+技术得到更广泛的应用.

初始化COM环境的目的是使调用COM的API工作正常,也就是在COM操作之前调用 ::CoInitialize或 ::CoInitializeEx就可以。位置不重要。

(注意,必须是之前!)

 

3.tlb、tlh和tli文件的关系 :

 tlb文件:com类型库文件。在需要使用对应com类的模块里,“#import ...*.tlb”使用之。
tlh、tli文件:他们是vc++编译器解析tlb文件生成的标准c++文件。因为odl和tlb并不是C++标准的东东,有必要把它们翻译成标准的C++类型,使得C++开发者可以使用。相信vb和j++也会把tlb翻译成自己语言兼容的类型描述信息。tlh相当于类型申明(头文件),tli相当于定义实现(CPP文件)。可以用写字板打开查看其内容。

备注一个重要的相关问题:
在VC下#import   "A.tlb"   no_namespace   named_guids;编译后产生A.tlh和A.tli两个文件,但把TLB文件更新后,相应的两个文件没有更新。为什么?
如果更新了tlb文件,需要在菜单里选择全部重新编译,否则编译器仍然会认为.tlh和.tli文件是最新的。

 

4.关于C++中的__uuidof :

1.简述

格式:__uuidof(表达式) __uuidof关键字用来获得表达式的GUID。这个表达式可以是一种类型名称、一个指针、引用或者一个类型的数组、一个有这个类型实例化的模板或者这种类型的变量。只要编译器能使用该参数获得相关的GUID,那么该参数就是有效的。 这个参数的特殊情况就是它取0或NULL的时候。在这种情况下,__uuidof会返回一个由0组成的GUID。 可以使用这一关键字来提取一个对象uuid扩展属性的GUID。

用来获取 某种结构、接口及其指针、引用、变量 所关联的GUID,类似于某些语言中获取类型 typeof 这样的操作。

2.使用

假定c++中,有结构体s

struct s {  int i; };123

可以通过下面的__declspec 给这个结构 关联一个GUID

struct __declspec( uuid("93A1665E-C9FA-4147-AC3A-3CC855281AF8") ) s;1

以后程序中使用该结构

s a = ...; s *b = ...; s &c = ...;123

通过__uuidof(s); __uuidof(a); __uuidof(b); __uuid(c); 都能得到结构s关联的GUID (“93A1665E-C9FA-4147-AC3A-3CC855281AF8”)

--------------------- 作者:Vasilisyl 来源:CSDN 原文:https://blog.csdn.net/qq_37354286/article/details/82292437 版权声明:本文为博主原创文章,转载请附上博文链接!

5.C++中Cstring使用小结

CString类功能强大,比STL的string类有过之无不及.新手使用CString时,都会被它强大
的功能所吸引.然而由于对它内部机制的不了解,新手在将CString向C的字符数组转换时
容易出现很多问题.因为CString已经重载了LPCTSTR运算符,所以CString类向const
char *转换时没有什么麻烦,如下所示:
char a[100];
CString str("aaaaaa");
strncpy(a,(LPCTSTR)str,sizeof(a));
或者如下:
strncpy(a,str,sizeof(a));
以上两种用法都是正确地.因为strncpy的第二个参数类型为const char *.所以编译器
会自动将CString类转换成const char *.很多人对LPCTSTR是什么东西迷惑不解,让我们
来看看:
1.LP表示长指针,在win16下有长指针(LP)和短指针(P)的区别,而在win32下是没有区别
的,都是32位.所以这里的LP和P是等价的.
2.C表示const
3.T是什么东西呢,我们知道TCHAR在采用UNICODE方式编译时是wchar_t,在普通时编译成char
那么就可以看出LPCTSTR(PCTSTR)在UINCODE时是const wchar_t *,PCWSTR,LPCWSTR,在
多字节字符模式时是const char *,PCSTR,LPCSTR.
接下来我们看在非UNICODE情况下,怎样将CString转换成char *,很多初学者都为了方便
采用如下方法:
(char *)(LPCSTR)str.这样对吗?我们首先来看一个例子:
 CString str("aa");
strcpy((char *)(LPCTSTR)str,"aaaaaaaa");
 cout<<(LPCTSTR)str<<endl;
在Debug下运行出现了异常,我们都知道CString类内部有自己的字符指针,指向一个已分
配的字符缓冲区.如果往里面写的字符数超出了缓冲区范围,当然会出现异常.但这个程
序在Release版本下不会出现问题.原来对CString类已经进行了优化.当需要分配的内存
小于64字节时,直接分配64字节的内存,以此类推,一般CString类字符缓冲区的大小为
64,128,256,512...这样是为了减少内存分配的次数,提高速度.
那有人就说我往里面写的字符数不超过它原来的字符数,不就不会出错了,比如
CString str("aaaaaaa");
strcpy((char *)(LPCTSTR)str,"aa");
cout<<(LPCTSTR)str<<endl;
这样看起来是没什么问题.我们再来看下面这个例子:
CString str("aaaaaaa");
strcpy((char *)(LPCTSTR)str,"aa");
cout<<(LPCTSTR)str<<endl;
cout<<str.GetLength()<<endl;
我们看到str的长度没有随之改变,继续为7而不是2.还有更严重的问题:
 CString str("aaaaaaa");
 CString str1 = str;
 strcpy((char *)(LPCTSTR)str,"aa");
 cout<<(LPCTSTR)str<<endl;
 cout<<(LPCTSTR)str1<<endl;
按说我们只改变了str,str1应该没有改变呀,可是事实时他们都变成了"aa".难道str和
str1里面的字符指针指向的缓冲区是一个.我们在Effective C++里面得知,如果你的类
内部有包含指针,请为你的类写一个拷贝构造函数和赋值运算符.不要让两个对象内部的
指针指向同一区域,而应该重新分配内存.难道是微软犯了错?
原来这里还有一个"写时复制"和"引用计数"的概念.CString类的用途很广,这样有可能
在系统内部产生大量的CString临时对象.这时为了优化效率,就采用在系统软件内部广
泛使用的"写时复制"概念.即当从一个CString产生另一个CString并不复制它的字符缓
冲区内容,而只是将字符缓冲区的"引用计数"加1.当需要改写字符缓冲区内的内容时,才
分配内存,并复制内容.以后我会给出一个"写时复制"和"引用计数"的例子
我们回到主题上来,当我们需要将CString转换成char *时,我们应该怎么做呢?其时只是
麻烦一点,如下所示:
CString str("aaaaaaa");
strcpy(str.GetBuffer(10),"aa");
str.ReleaseBuffer();
当我们需要字符数组时调用GetBuffer(int n),其中n为我们需要的字符数组的长度.使
用完成后一定要马上调用ReleaseBuffer();
还有很重要的一点就是,在能使用const char *的地方,就不要使用char *

另外:我在代码中使用下列的方法,也是正确
CString str("aaaaaaa");
strcpy(str.GetBuffer(1),"ababasdfrywyeuyeghdfvbedtrhyertywetrgsdf");
/// here  use str

str.ReleaseBuffer();

Cstring 直接转换为指针时

Cstring str1;
Char *p;
p = str1.GetBuffer(str1.GetLength());  ----------OK;
p =  (LPCTSTR)str1;                         -----------OK;

 

c++中LPCTSTR,LPTSTR 解释:

 

char是C语言标准数据类型,字符型,至于由几个字节组成通常由编译器决定,一般一个字节。Windows为了消除各编译器的差别,重新定义了一些数据类型,你提到了另外几个类型都是这样。CHAR为单字节字符。还有个WCHAR为Unicode字符,即不论中英文,每个字有两个字节组成。它实际定义在<string.h>里: typedef unsigned short wchar_t。

 

下面在看看TCHAR。如果你希望同时为ANSI和Unicode编译的源代码,那就要include TChar.h。TCHAR是定义在其中的一个宏,它视你是否定义了_UNICODE宏而定义成char或者wchar_t。如果当前编译方式为ANSI(默认)方式,TCHAR等价于CHAR,如果为Unicode方式,TCHAR等价于WCHAR。

 

不能使用类似strcpy这样的ANSI C字符串函数来处理wchar_t字符串,必须使用wcs前缀的函数,例如wcscpy。为了让编译器识别Unicode字符串,必须以在前面加一个“L”,例如:  wchar_t *szTest=L"This is a Unicode string.";

 

 如果你使用了TCHAR,那么就不应该使用ANSI的strXXX函数或者Unicode的wcsXXX函数了,而必须使用TChar.h中定义的_tcsXXX函数。另外,为了解决刚才提到带“L”的问题,TChar.h中定义了一个宏:“_TEXT”。

 

 以strcpy函数为例子,总结一下:  .如果你想使用ANSI字符串,那么请使用这一套写法:  char szString[100];  strcpy(szString,"test");  .如果你想使用Unicode字符串,那么请使用这一套:  wchar_t szString[100];  wcscpyszString,L"test");  .如果你想通过定义_UNICODE宏,而编译ANSI或者Unicode字符串代码:  TCHAR szString[100];  _tcscpy(szString,_TEXT("test"));

 

 

 

在当前版本LPCSTR和LPSTR没区别,即以零结尾的字符串指针,相当于CHAR *。

 

LPCSTR       A   32-bit   pointer   to   a   constant   character   string.      常量指针,一般用于参数传递和固定字符串           LPSTR       A   32-bit   pointer   to   a   character   string.      普通指针,一般用于字符串操作           根据DBCS或Unicode   自动选择char或wchar_t类型,由定义的宏_UNICODE决定      LPCTSTR       A   32-bit   pointer   to   a   constant   character   string   that   is   portable   for   Unicode   and   DBCS.           LPTSTR       A   32-bit   pointer   to   a   character   string   that   is   portable   for   Unicode   and   DBCS.

 

 

 

一个转换CString 的例子。

 

 

 

 CString str = "ABC";

 

LPCTSTR ptr1 = new TCHAR[str.GetLength()+1]; ptr1 = (LPCTSTR) str.GetBuffer();

 

LPTSTR ptr2 = new TCHAR[str.GetLength()+1]; ptr2 = (LPTSTR) str.GetBuffer();

 

LPSTR ptr3 = new char[str.GetLength()+1]; ptr3 = (LPSTR) str.GetBuffer();

 

LPCSTR ptr4 = new char[str.GetLength()+1]; ptr4 = (LPCSTR) str.GetBuffer();

 

 

 

另外,要注意选用的函数也要和string类型一致。比如下面:tmp1=144,tmp2=1,因为sLastChan为宽字节,存储为310034003400, atoi函数遇到第一个"00"就会结束。

 

   CString sLastChan = _T("144");    int tmp1 = _tstoi((TCHAR*)sLastChan.GetBuffer(sLastChan.GetLength()));    tmp2 = atoi((char*)sLastChan.GetBuffer(sLastChan.GetLength()));

 

//百科

 

由于Win32 API文档的函数列表使用函数的常用名字(例如, SetWindowText"),所有的字符串都是用TCHAR来定义的。(除了XP中引入的只适用于Unicode的API)。

 

LPTSTR解释

 

编辑

 

表示指向字符/字符串的指针。WINDOWS 下面的程序设计可以支持MBCS和UNICODE两种编码的字符串,具体用那种就看你定义了MBCS宏还是UNICODE宏。MBCS宏对应的字符串指针 是char*也就是LPSTR,UNICODE对应的指针是unsigned short*也就是LPWSTR,为了写程序方便微软定义了类型LPTSTR,在MBCS下它就是char*,在UNICODE下它是unsigned char*,这样你就可以重定义一个宏进行不同字符集的转换了。

 

LP:长指针(long pointer)。

 

T:win32环境中有一个_T宏,用来标识字符是否采用Unicode编码(两字节表示一个字符),若程序中定义了Unicode,该字符/字符串被作为Unicode字符串,否则就是标准的ANSI(单字节表示一个字符)字符串。

 

STR:表示这个变量是一个字符串。

 

/* LPTSTR 转换成 CString */

 

(1)直接赋值

 

CString strText;

 

LPTSTR lpszText = _T("LPTSTR >> CString");

 

strText = lpszText;

 

::MessageBox( NULL, strText , _T("标题"), MB_ICONASTERISK|MB_TASKMODAL|MB_OK );

 

(2)CString::Format()格式化

 

CString strText;

 

LPTSTR lpszText = _T("LPTSTR >> CString");

 

strText.Format( _T("%s"), lpszText );

 

::MessageBox( NULL, strText , _T("标题"), MB_ICONASTERISK|MB_TASKMODAL|MB_OK );

 

/* CString 转换成 LPTSTR */

 

(1)强制转换

 

CString strText( _T("This is a test") );

 

LPTSTR lpszText =(LPTSTR)(LPCTSTR)strText;

 

::MessageBox( NULL, lpszText, _T("标题"), MB_ICONASTERISK|MB_TASKMODAL|MB_OK );

 

(2)使用lstrcpy()

 

CString strText( "This is a test" );

 

LPTSTR lpszText = new TCHAR[strText.GetLength()+1];

 

lstrcpy( lpszText, strText );

 

::MessageBox( NULL, lpszText, _T("标题"), MB_ICONASTERISK|MB_TASKMODAL|MB_OK );

 

(3)使用CString::GetBuffer()

 

CString strText(_T("This is a test "));

 

LPTSTR lpszText = strText.GetBuffer();

 

strText.ReleaseBuffer();

 

::MessageBox( NULL, lpszText, _T("标题"), MB_ICONASTERISK|MB_TASKMODAL|MB_OK );

 

/* char * 转换成 CString

 

char chArray[] = "This is a test";

 

char * p = "This is a test";

 

CString theString = chArray;

 

theString.Format(_T("%s"), chArray);

 

theString = p;

 

/* CString转换成char*

 

1.

 

CString theString( "This is a test" );

 

LPTSTR lpsz = new TCHAR[theString.GetLength()+1];

 

_tcscpy(lpsz, theString);

 

2.

 

CString s(_T("Char test "));

 

LPTSTR p = s.GetBuffer(); [1] 

 

LPTSTR dot = strchr(p, ''.'');

 

// 在这里添加使用p的代码

 

if(p != NULL)

 

*p = _T('');

 

s.ReleaseBuffer();

 

 

c++中LPTSTR

 

编辑

 

LPCTSTR,LPWSTR, PTSTR, LPTSTR,wchar_t区别

 

L表示long指针,这是为了兼容Windows 3.1等16位操作系统遗留下来的,在win32中以及其他的32位操作系统中, long指针和near指针及far修饰符都是为了兼容的作用,没有实际意义。即win32中,long,near,far指针与普通指针没有区别,LP与P是等效的。

 

P表示这是一个指针。

 

T表示_T宏,这个宏用来表示你的字符是否使用UNICODE, 如果你的程序定义了UNICODE或者其他相关的宏,那么这个字符或者字符串将被作为UNICODE字符串,否则就是标准的ANSI字符串。

 

STR表示这个变量是一个字符串。

 

C表示是一个常量,const。

 

LPTSTR:

 

如果定义了UNICODE宏则LPTSTR被定义为LPWSTR。typedef LPTSTR LPWSTR;

 

否则LPTSTR被定义为LPSTR。 typedef LPTSTR LPSTR;

 

下面列出一些常用的typedefs:

 

类型 MBCS Unicode

 

WCHARwchar_twchar_t

 

LPSTR char* char*

 

LPCSTR const char* const char*

 

LPWSTRwchar_t* wchar_t*

 

LPCWSTR constwchar_t* const wchar_t*

 

TCHAR charwchar_t

 

LPTSTR TCHAR*(或char*) TCHAR* (或wchar_t*)

 

LPCTSTR const TCHAR* const TCHAR*

 

所以结论,在VS2005系统中,为提高可移植性,定义字符串时用TCHAR,转化为UNICODE时用_T而不用L。

 

7.c++中__declspec用法总结

 

“__declspec”是Microsoft c++中专用的关键字,它配合着一些属性可以对标准C++进行扩充。这些属性有:align、allocate、deprecated、 dllexport、dllimport、 naked、noinline、noreturn、nothrow、novtable、selectany、thread、property和uuid。
1,_declspec (1)用法一定义接口

 

#include <IOSTREAM> using namespace std; #define interface class __declspec(novtable) interface ICodec

 

ICodec 同等于如下:

 

1class ICodec 2{ 3public: 4    virtual bool Decode(char * lpDataSrc,unsigned int nSrcLen,char * lpDataDst,unsigned int *pnDstLen)=0; 5    virtual bool Encode(char * lpDataSrc,unsigned int nSrcLen,char * lpDataDst,unsigned int *pnDstLen)=0; 6};
2,用法二,定义类的属性 属性,是面向对象程序设计中不可缺少的元素,广义的属性是用来描述一个对象所处于的状态。而我们这篇文章所说的属性是狭义的,指能用“=”操作符对类的一个数据进行get或set操作,而且能控制get和set的权
 1#include <IOSTREAM>  2#include <map>  3#include <string>  4#include <CONIO.H>  5using namespace std;  6  7class propertytest  8

 

如,

 

#define Test_API __declspec(dllexport) Class test

 

 

 

4. __declspec(align(16)) struct SS{ int a,b; };  它与#pragma pack()是一对兄弟,前者规定了对齐的最小值,后者规定了对齐的最大值。同时出现时,前者优先级高。 __declspec(align())的一个特点是,它仅仅规定了数据对齐的位置,而没有规定数据实际占用的内存长度,当指定的数据被放置在确定的位置之后,其后的数据填充仍然是按照#pragma pack规定的方式填充的,这时候类/结构的实际大小和内存格局的规则是这样的:在__declspec(align())之前,数据按照#pragma pack规定的方式填充,如前所述。当遇到__declspec(align())的时候,首先寻找距离当前偏移向后最近的对齐点(满足对齐长度为max (数据自身长度,指定值)),然后把被指定的数据类型从这个点开始填充,其后的数据类型从它的后面开始,仍然按照#pragma pack填充,直到遇到下一个__declspec(align())。当所有数据填充完毕,把结构的整体对齐数值和__declspec(align ())规定的值做比较,取其中较大的作为整个结构的对齐长度。 特别的,当__declspec(align())指定的数值比对应类型长度小的时候,这个指定不起作用。

 

5. #pragma section("segname",read)     / __declspec(allocate("segname")) int i = 0;     / int main(){ return 1;};  此关键词必须跟随code_seg,const_seg,data_seg,init_seg,section关键字之后使用,以上例子使用了section关键字。使用此关键字将告知编译器,其后的变量间被分配在那个数据段。

 

6. __declspec(deprecated(MY_TEXT)) void func(int) {}  与pragma deprecated()相同。此声明后,如果在同一作用域中使用func(int)函数,将被提醒c4996警告。

 

7. __declspec(jitintrinsic)  用于标记一个函数或元素为64位公共语言运行时。具体用法未见到。

 

8. __declspec( naked ) int func( formal_parameters ) {}  此关键字仅用于x86系统,多用于硬件驱动。此关键字可以使编译器在生成代码时不包含任何注释或标记。仅可以对函数的定义使用,不能用于数据声明、定义,或者函数的声明。

 

9. __declspec(restrict) float * init(int m, int n) {};    & __declspec(noalias) void multiply(float * a, float * b, float * c) {};// 优化必用!  __declspec (restrict)仅适用于返回指针的函数声明,如 __declspec(restrict) void *malloc(size_t size);restrict declspec 适用于返回非别名指针的函数。此关键字用于 malloc 的 C 运行时库实现,因为它决不会返回已经在当前程序中使用的指针值(除非您执行某个非法操作,如在内存已被释放之后使用它)。restrict declspec 为编译器提供执行编译器优化的更多信息。对于编译器来说,最大的困难之一是确定哪些指针会与其他指针混淆,而使用这些信息对编译器很有帮助。有必要指出,这是对编译器的一个承诺,编译器并不对其进行验证。如果您的程序不恰当地使用 restrict declspec,则该程序的行为会不正确。 __declspec(noalias)也是仅适用于函数,它指出该函数是半纯粹的函数。半纯粹的函数是指仅引用或修改局部变量、参数和第一层间接参数。此 declspec 是对编译器的一个承诺,如果该函数引用全局变量或第二层间接指针参数,则编译器会生成将中断应用程序的代码。

 

10. class X {    / __declspec(noinline) int mbrfunc() { return 0; /* will not inline*/ };  在类中声明一个函数不需要内联。

 

11. __declspec(noreturn) extern void fatal () {}  不需要返回值。

 

12. void __declspec(nothrow) __stdcall f2();  不存在异常抛出。

 

13. struct __declspec(novtable) X { virtual void mf(); };     / struct Y : public X {void mf() {printf_s("In Y/n");}};  此关键字标记的类或结构不能直接实例化,否则将引发AV错误(access violation)。此关键字的声明将阻止编译器对构造和析构函数的vfptr的初始化。可优化编译后代码大小。

 

12. struct S {   int i;     / void putprop(int j) {  i = j; }     / int getprop() { return i; }     / __declspec(property(get = getprop, put = putprop)) int the_prop;};   此关键字与C#中get & set属性相同,可定义实现针对一个字段的可读或可写。以上例子,可以使用(如果实例化S为ss)如:ss.the_prop = 156;(此时,ss.i == 156)接着如果:cout<< s.the_prop;(此时将调用getprop,使返回156)。

 

14. __declspec(selectany)(转)  在MFC,ATL的源代码中充斥着__declspec (selectany)的声明。selectany可以让我们在.h文件中初始化一个全局变量而不是只能放在.cpp中。比如有一个类,其中有一个静态变量,那么我们可以在.h中通过类似__declspec(selectany) type class::variable = value; 这样的代码来初始化这个全局变量。既是该.h被多次include,链接器也会为我们剔除多重定义的错误。对于template的编程会有很多便利。

 

15. __declspec(thread) int in_One_Thread;  声明in_One_Thread为线程局部变量并具有线程存储时限,以便链接器安排在创建线程时自动分配的存储。

 

16. struct __declspec(uuid("00000000-0000-0000-c000-000000000046")) IUnknown;  将具有唯一表示符号的已注册内容声明为一个变量,可使用__uuidof()调用。

 

推荐阅读