C++异常捕获try
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C++的try_catch异常
今天写了个程序退出却没有任何捕获所以猛补一课。
一、简单的例子
首先通过一个简单的例子来熟悉C++ 的try/catch/throw:
1 #include<iostream.h> //包含头文件
2 #include<stdlib.h>
3 double fuc(double x, double y) //定义函数
4 {
5 if(y==0)
6 {
7 throw y; //除数为0,抛出异常
8 }
9 return x/y; //否则返回两个数的商
10 }
11 void main()
12 {
13 double res;
14 try //定义异常
15 {
16 res=fuc(2,3);
17 cou t<<"The result of x/y is : "<<res<<endl;
18 res=fuc(4,0); //出现异常
19 }
20 catch(double) //捕获并处理异常
21 {
22 cerr<<"error of dividing zero.\n";
23 exit(1); //异常退出程序
24 }
25 }
catch 的数据类型需要与throw出来的数据类型相匹配的。
二、catch(...)的作用
catch(…)能够捕获多种数据类型的异常对象,所以它提供给程序员一种对异常对象更好的控制手段,使开发的软件系统有很好的可靠性。
因此一个比较有经验的程序员通常会这样组织编写它的代码模块,如下:
void Fu nc()
{
try
{
// 这里的程序代码完成真正复杂的计算工作,这些代码在执行过程中
// 有可能抛出DataType1、DataType2和DataType3类型的异常对象。
}
catch(DataType1& d1)
{
}
catch(DataType2& d2)
{
}
catch(DataType3& d3)
{
}
// 注意上面try block中可能抛出的DataType1、DataType2和DataType3三
// 种类型的异常对象在前面都已经有对应的catch block来处理。
但为什么
// 还要在最后再定义一个catch(…) block呢?这就是为了有更好的安全性和// 可靠性,避免上面的try block抛出了其它未考虑到的异常对象时导致的程// 序出现意外崩溃的严重后果,而且这在用VC开发的系统上更特别有效,因// 为catch(…)能捕获系统出现的异常,而系统异常往往令程序员头痛了,现// 在系统一般都比较复杂,而且由很多人共同开发,一不小心就会导致一个// 指针变量指向了其它非法区域,结果意外灾难不幸发生了。
catch(…)为这种// 潜在的隐患提供了一种有效的补救措施。
catch(…)
{
}
}
三、异常中采用面向对象的处理
首先看下面的例子:
void OpenFile(string f)
{
try
{
// 打开文件的操作,可能抛出FileOpenException
}
catch(FileOpenException& fe)
{
// 处理这个异常,如果这个异常可以很好的得以恢复,那么处理完毕后函数 // 正常返回;否则必须重新抛出这个异常,以供上层的调用函数来能再次处 // 理这个异常对象
int result = ReOpenFile(f);
if (result == false) throw;
}
}
void R eadFile(File f)
{
try
{
// 从文件中读数据,可能抛出FileR eadException
}
catch(FileReadException& fe)
{
// 处理这个异常,如果这个异常可以很好的得以恢复,那么处理完毕后函数
// 正常返回;否则必须重新抛出这个异常,以供上层的调用函数来能再次处
// 理这个异常对象
int result = ReReadFile(f);
if (result == false) throw;
}
}
void WriteFile(File f)
{
try
{
// 往文件中写数据,可能抛出FileWriteException
}
catch(FileWriteException& fe)
{
// 处理这个异常,如果这个异常可以很好的得以恢复,那么处理完毕后函数
// 正常返回;否则必须重新抛出这个异常,以供上层的调用函数来能再次处理这个异常对象 int result = ReWriteFile(f);
if (result == false) throw;
}
}
void Fu nc()
{
try
{
// 对文件进行操作,可能出现FileWriteException、FileWriteException
// 和FileWriteException异常
OpenFile(…);
ReadFile(…);
WriteFile(…);
}
// 注意:FileException是FileOpenException、FileReadException和FileWriteException
// 的基类,因此这里定义的catch(FileException& fe)能捕获所有与文件操作失败的异
// 常。
catch(FileException& fe)
{
ExceptionInfo* ef = fe.GetExceptionInfo();
cou t << “操作文件时出现了不可恢复的错误,原因是:”<< fe << endl;
}
}
下面是更多面向对象和异常处理结合的例子:
#include <iostream.h>
class ExceptionClass
{
char* name;
public:
ExceptionClass(const char* name="default name")
{
cou t<<"Construct "<<name<<endl;
this->name=name;
}
~ExceptionClass()
{
cou t<<"Destruct "<<name<<endl;
}
void mythrow()
{
throw ExceptionClass("my throw");
}
}
void main()
{
ExceptionClass e("Test");
try
{
e.mythrow();
}
catch(...)
{
cou t<<”*********”<<endl;
}
}
这是输出信息:
Construct Test
Construct my throw
Destruct my throw
****************
Destruct my throw (这里是异常处理空间中对异常类的拷贝的析构)Destruct Test
======================================
不过一般来说我们可能更习惯于把会产生异常的语句和要throw的异常类分成不同的类来写,下面的代码可以是我们更愿意书写的:
class ExceptionClass
{
public:
ExceptionClass(const char* name="Exception Default Class")
{
cou t<<"Exception Class Construct String"<<endl;
}
~ExceptionClass()
{
cou t<<"Exception Class Destruct String"<<endl;
}
void R eportError()
{
cou t<<"Exception Class:: This is Report Error Message"<<endl;
}
};
class ArguClass
{
char* name;
public:
ArguClass(char* name="default name")
{
cou t<<"C onstruct String::"<<name<<endl;
this->name=name;
}
~ArguClass()
{
cou t<<"Destruct S tring::"<<name<<endl;
}
void mythrow()
{
throw ExceptionClass("my throw");
}
};
_tmain()
{
ArguClass e("haha");
try
e.mythrow();
}
catch(int)
{
cout<<"If This is Message display screen, This is a Error!!"<<endl; //这行不会执行
}
catch(ExceptionClass pTest)
{
pTest.ReportError();
}
catch(...)
{
cou t<<"***************"<<endl;
}
}
输出Message:
Construct String::haha
Exception Class C onstruct String
Exception Class Destruct S tring
Exception Class:: This is Report Error Message
Exception Class Destruct S tring
Destruct String::haha
四、构造和析构中的异常抛出
先看个程序,假如我在构造函数的地方抛出异常,这个类的析构会被调用吗?可如果不调用,那类里的东西岂不是不能被释放了?
#include <iostream.h>
#include <stdlib.h>
class ExceptionClass1
{
char* s;
public:
ExceptionClass1()
{
cout<<"ExceptionClass1()"<<endl;
s=new char[4];
cout<<"throw a exception"<<endl;
throw 18;
}
~ExceptionClass1()
cout<<"~ExceptionClass1()"<<endl;
delete[] s;
}
};
void main()
{
try
{
ExceptionClass1 e;
}
catch(...)
{}
}
结果为:
ExceptionClass1()
throw a exception
在这两句输出之间,我们已经给S分配了内存,但内存没有被释放(因为它是在析构函数中释放的)。
应该说这符合实际现象,因为对象没有完整构造。
为了避免这种情况,我想你也许会说:应避免对象通过本身的构造函数涉及到异常抛出。
即:既不在构造函数中出现异常抛出,也不应在构造函数调用的一切东西中出现异常抛出。
但是在C++中可以在构造函数中抛出异常,经典的解决方案是使用S TL的标准类auto_ptr。
那么,在析构函数中的情况呢?我们已经知道,异常抛出之后,就要调用本身的析构函数,如果这析构函数中还有异常抛出的话,则已存在的异常尚未被捕获,会导致异常捕捉不到。
五、标准C++异常类
标准异常都派生自一个公共的基类exception。
基类包含必要的多态性函数提供异常描述,可以被重载。
下面是exception 类的原型:
class exception
{
public:
exception() throw();
exception(const exception& rhs) throw();
exception& operator=(const exception& rhs) throw();
virtual ~exception() throw();
virtual const char *what() const throw();
};
C++有很多的标准异常类:
namespace std
{
//exception派生
class logic_error; //逻辑错误,在程序运行前可以检测出来
//logic_error派生
class domain_error; //违反了前置条件
class invalid_argument; //指出函数的一个无效参数
class leng th_error; //指出有一个超过类型size_t的最大可表现值长度的对象的企图
class out_of_range; //参数越界
class bad_cast; //在运行时类型识别中有一个无效的d ynamic_cast表达式
class bad_typeid; //报告在表达试typeid(*p)中有一个空指针p
//exception派生
class ru ntime_error; //运行时错误,仅在程序运行中检测到
//runtime_error派生
class range_error; //违反后置条件
class overflow_error; //报告一个算术溢出
class bad_alloc; //存储分配错误
}
标准库异常类定义在以下四个头文件中
1、exception头文件:定义了最常见的标准异常类,其类名为exception。
只通知异常的产生,但不会提供更多的信息
2、stdexcept头文件定义了以下几种常见异常类
函数功能或作用
exception 最常见的问题
runtime_error 运行时错误:仅在运行时才能检测到的问题
range_error 运行时错误:生成的结果超出了有意义的值域范围
overflow_error 运行时错误:计算上溢
underflow_error 运行时错误:计算下溢
logic_error 逻辑错误:可在运行前检测到的问题
domain_error 逻辑错误:参数的结果值不存在
invalid_argument 逻辑错误:不合适的参数
leng th_error 逻辑错误:试图生成一个超出该类型最大长度的对象
out_of_range 逻辑错误:使用一个超出有效范围的值
3、new头文件定义了bad_alloc异常类型,提供因无法分配内存而由new抛出的异常
4、type_info头文件定义了bad_cast异常类型(要使用type_info必须包含typeinfo头文件)下面是使用异常类的例子:
首先,我定义了几个异常类,这些类也可以从标准异常类进行派生,如下
class BadInitializers
{
public:
BadInitializers() {}
};
class Ou tOfB ounds
{
public:
OutOfB ounds(int i) { cou t<<"Size "<<i<<" is illegal!!!"<<endl; }
};
class SizeMismatch
{
public:
SizeMismatch() {}
};
然后要在程序中需要的地方使用throw来抛出异常类,两个抛出异常类的例子如下
template <class T>
Array1D<T>::Array1D(int sz)
{
if(sz<0)
{
//throw BadInitializers();
throw invalid_argu ment("Size has to be bigger than 0!!!");
}
size=sz;
element=new T[size];
}
template <class T>
T &Array1D<T>::operator[](int i) const
{
if(i<0||i>=size)
{
throw Ou tOfB ounds(i);
}
return element[i];
}
然后在主程序中使用try...catch...来捕获异常,并进行相应的处理,如下try
{
int i=0;
Array1D<int> a1(5);
a1[0]=1;
a1[1]=3;
a1[2]=5;
a1[3]=7;
a1[4]=8;
Array1D<int> a2(a1);
for(i=0;i<a2.Size();i++)
{
cou t<<a2[i]<<" ";
}
cout<<endl;
Array1D<int> a3(5);
a3=a1+a2;
cout<<a3;
}
catch(Bad Initializers)
{
cout<<"Error:B adInitializers!!!"<<endl;
}
catch(OutOfB ounds &e)
{
cout<<"Error:OutOfB ounds!!!"<<endl;
}
catch(SizeMismatch &e)
{
cout<<"Error:SizeMismatch!!!"<<endl;
}
catch(invalid_argument &e)
{
cout<<"Error:"<<e.what()<<endl;
}
catch(...)
{
cout<<"An u nknown error!!!"<<endl;
}
六、try finally使用
__try
{
file://保护块
}
__finally
{
file://结束处理程序
}
在上面的代码段中,操作系统和编译程序共同来确保结束处理程序中的__f i n a l l y代码块能够被执行,不管保护体(t r y块)是如何退出的。
不论你在保护体中使用r e t u r n,还是g o t o,或者是longjump,结束处理程序(f i n a l l y块)都将被调用。
我们来看一个实列:(返回值:10, 没有Leak,性能消耗:小)
DWORD Func_SEHTerminateHandle()
{
DWORD dwReturnData = 0;
HANDLE hSem = NULL;
const char* lpSemName = "TermSem";
hSem = CreateSemaphore(NULL, 1, 1, lpSemName);
__try
{
WaitForSingleObject(hSem,INFINITE);
dwReturnData = 5;
}
__finally
{
ReleaseSemaphore(hSem,1,NULL);
CloseHandle(hSem);
}
dwReturnData += 5;
return dwReturnData;
}
这段代码应该只是做为一个基础函数,我们将在后面修改它,来看看结束处理程序的作用:
====================
在代码加一句:(返回值:5, 没有Leak,性能消耗:中下)
DWORD Func_SEHTerminateHandle()
{
DWORD dwReturnData = 0;
HANDLE hSem = NULL;
const char* lpSemName = "TermSem";
hSem = CreateSemaphore(NULL, 1, 1, lpSemName);
__try
WaitForSingleObject(hSem,INFINITE);
dwReturnData = 5;
retu rn dwReturnData;
}
__finally
{
ReleaseSemaphore(hSem,1,NULL);
CloseHandle(hSem);
}
dwReturnData += 5;
return dwReturnData;
}
在try块的末尾增加了一个return语句。
这个return语句告诉编译程序在这里要退出这个函数并返回dw Temp变量的内容,现在这个变量的值是5。
但是,如果这个return语句被执行,该线程将不会释放信标,其他线程也就不能再获得对信标的控制。
可以想象,这样的执行次序会产生很大的问题,那些等待信标的线程可能永远不会恢复执行。
通过使用结束处理程序,可以避免return语句的过早执行。
当return语句试图退出try块时,编译程序要确保finally块中的代码首先被执行。
要保证finally块中的代码在try块中的return语句退出之前执行。
在程序中,将ReleaseSemaphore 的调用放在结束处理程序块中,保证信标总会被释放。
这样就不会造成一个线程一直占有信标,否则将意味着所有其他等待信标的线程永远不会被分配C PU时间。
在finally块中的代码执行之后,函数实际上就返回。
任何出现在finally块之下的代码将不再执行,因为函数已在try块中返回。
所以这个函数的返回值是5,而不是10。
读者可能要问编译程序是如何保证在try块可以退出之前执行finally块的。
当编译程序检查源代码时,它看到在try块中有retu rn语句。
这样,编译程序就生成代码将返回值(本例中是5)保存在一个编译程序建立的临时变量中。
编译程序然后再生成代码来执行f i n a l l y块中包含的指令,这称为局部展开。
更特殊的情况是,由于try块中存在过早退出的代码,从而产生局部展开,导致系统执行finally块中的内容。
在finally块中的指令执行之后,编译程序临时变量的值被取出并从函数中返回。
可以看到,要完成这些事情,编译程序必须生成附加的代码,系统要执行额外的工作。
finally块的总结性说明
我们已经明确区分了强制执行finally块的两种情况:
• 从try块进入finally块的正常控制流。
• 局部展开:从try块的过早退出(goto、long jump、continue、break、return等)强制控制转移到finally块。
第三种情况,全局展开(global unwind),这个以后再看。
七、C++异常参数传递
从语法上看,在函数里声明参数与在catch子句中声明参数是一样的,catch里的参数可以是值类型,引用类型,指针类型。
例如:
try
{
.....
}
catch(A a)
{
catch(B& b)
{
}
catch(C* c)
{
}
尽管表面是它们是一样的,但是编译器对二者的处理却又很大的不同。
调用函数时,程序的控制权最终还会返回到函数的调用处,但是抛出一个异常时,控制权永远不会回到抛出异常的地方。
class A;
void func_throw()
{
A a;
throw a; //抛出的是a的拷贝,拷贝到一个临时对象里
}
try
{
func_throw();
}
catch(A a) //临时对象的拷贝
{
}
当我们抛出一个异常对象时,抛出的是这个异常对象的拷贝。
当异常对象被拷贝时,拷贝操作是由对象的拷贝构造函数完成的。
该拷贝构造函数是对象的静态类型(static type)所对应类的拷贝构造函数,而不是对象的动态类型(d ynamic type)对应类的拷贝构造函数。
此时对象会丢失R TTI信息。
异常是其它对象的拷贝,这个事实影响到你如何在catch块中再抛出一个异常。
比如下面这两个catch块,乍一看好像一样:
catch (A& w) // 捕获异常
{
// 处理异常
throw; // 重新抛出异常,让它继续传递
}
catch (A& w) // 捕获Widget异常
{
// 处理异常
throw w; // 传递被捕获异常的拷贝
}
第一个块中重新抛出的是当前异常(current exception),无论它是什么类型。
(有可能是A的派生类)
第二个catch块重新抛出的是新异常,失去了原来的类型信息。
一般来说,你应该用throw来重新抛出当前的异常,因为这样不会改变被传递出去的异常类型,而且更有效率,因为不用生成一个新拷贝。
看看以下这三种声明:
catch (A w) ... // 通过传值
catch (A& w) ... // 通过传递引用,一个被异常抛出的对象(总是一个临时对象)可以通过普通的引用捕获
catch (const A& w) ... //const引用
回到异常对象拷贝上来。
我们知道,当用传值的方式传递函数的参数,我们制造了被传递对象的一个拷贝,并把这个拷贝存储到函数的参数里。
同样我们通过传值的方式传递一个异常时,也是这么做的当我们这样声明一个catch子句时: catch (A w) ... // 通过传值捕获
会建立两个被抛出对象的拷贝,一个是所有异常都必须建立的临时对象,第二个是把临时对象拷贝进w中。
实际上,编译器会优化掉一个拷贝。
同样,当我们通过引用捕获异常时,
catch (A& w) ... // 通过引用捕获
catch (const A& w) ... //const引用捕获
这仍旧会建立一个被抛出对象的拷贝:拷贝是一个临时对象。
相反当我们通过引用传递函数参数时,没有进行对象拷贝。
话虽如此,但是不是所有编译器都如此。
另外,通过指针抛出异常与通过指针传递参数是相同的。
不论哪种方法都是一个指针的拷贝被传递。
你不能认为抛出的指针是一个指向局部对象的指针,因为当异常离开局部变量的生存空间时,该局部变量已经被释放。
C atch子句将获得一个指向已经不存在的对象的指针。
这种行为在设计时应该予以避免。
另外一个重要的差异是在函数调用者或抛出异常者与被调用者或异常捕获者之间的类型匹配的过程不同。
在函数传递参数时,如果参数不匹配,那么编译器会尝试一个类型转换,如果存在的话。
而对于异常处理的话,则完全不是这样。
见一下的例子:
void func_throw()
{
CString a;
throw a; //抛出的是a的拷贝,拷贝到一个临时对象里
}
try
{
func_throw();
}
catch(const char* s)
{
}
抛出的是CString,如果用const char*来捕获的话,是捕获不到这个异常的。
尽管如此,在catch子句中进行异常匹配时可以进行两种类型转换。
第一种是基类与派生类的转换,一个用来捕获基类的catch子句也可以处理派生类类型的异常。
反过来,用来捕获派生类的无法捕获基类的异常。
第二种是允许从一个类型化指针(typed pointer)转变成无类型指针(untyped pointer),所以带有const void* 指针的catch子句能捕获任何类型的指针类型异常:
catch (const void*) ... //可以捕获所有指针异常
另外,你还可以用catch(...)来捕获所有异常,注意是三个点。
传递参数和传递异常间最后一点差别是catch子句匹配顺序总是取决于它们在程序中出现的顺序。
因此一个派生类异常可能被处
理其基类异常的catch子句捕获,这叫异常截获,一般的编译器会有警告。
class A {
public:
A()
{
cou t << "class A creates" << endl;
}
void print()
{
cou t << "A" << endl;
}
~A()
{
cou t << "class A destruct" << endl;
}
};
class B: public A
{
public:
B()
{
cou t << "class B create" << endl;
}
void print()
{
cou t << "B" << endl;
}
~B()
{
cou t << "class B destruct" << endl;
}
};
void func()
{
B b;
throw b;
}
try
{
func();
}
catch( B& b) //必须将B放前面,如果把A放前面,B放后面,那么B类型的异常会先被截获。
{
b.print();
}
catch (A& a)
a.print() ;
}
如何全局捕获
要通过C++的try和catch来捕获SE H异常是可以的,而且当你用了C++的内容有时候你必须要这么做,因为SE H的__try __catch以及__finally是不能和C++的类的对象和平共处的,会出现编译错误。
实现起来你有一些铺垫要做。
首先你要写一个类,随便一个类,比如叫class E xception,类可以什么都没有,一个空的就可以了。
然后,修改编译器的选项,在Code Generation里面有一个的C++异常选项,选择抛出C++异常,VC版本不同,选项地方也不同很难和你描述,但是选上之后的效果就是给编译器增加了/E Ha 的开关,默认的可能是/E Hsc。
然后做最后一步,写一个全局函数,比如:
void throw_exception( unsigned int code, E XCEPTION_P OINTE RS* ptr)
{
throw E xception(); // 这个函数要做的就是抛出一个C++的异常,至于抛出什么随便你。
}
这个函数的形参必须是像上面所举的例子一样,注意要包含eh.h头文件。
然后在程序一开头,调用函数
_set_se_translator将你写的函数指针告诉它:
_set_se_translator(thro w_exception);
这样就大功告成了,当出现系统异常的时候,你的函数就会被调用,你在函数里抛出异常就可以被你的catch环节给逮到。
我贴个示例代码,稍微复杂一点,E xception类保留了异常代码和异常指针,可以供程序分析使用。
代码捕获了故意产生的访问违规,并使程序继续执行而不被Windows关闭。
#include <stdio.h>
#include <eh.h>
// 别忘记将编译器设定成/E Ha!
class E xception
{
public:
E xception(unsigned int _code, E XCEPTION_P OINTERS* _ptr)
: code(_code), ptrE xception(_ptr) {}
~E xception() {}
unsigned int code;
E XCEPTION_P OINTERS* ptr E xception;
};
void throw_exception( unsigned int code, E XCEPTION_P OINTE RS* ptr)
throw E xception(code, ptr);
}
int main(int argc, char* argv[])
{
_set_se_translator(thro w_exception); //你可以注释掉这一句,这样就不会抛出异常,后面的访问违规就不会被捕获,程序一运行立刻被Windows枪毙,最后一行的printf也不会被执行
// 故意产生一个访问违规
int* pointer = NULL;
try
{
*pointer = 100; // 对零指针操作产生访问违规,不捕获异常Windows会将程序强制关闭
}
catch (E xception e)
{
printf("E xception caught!\n");
// 这里你还能确定具体出现了何种异常
if (e.ptrE xception->E xceptionRecord->E xceptionCode
== E XCEPTION_ACCE SS_VIOLATION)
{
printf("It's access violation!\n");
}
}
printf("The program is running...\n");
}
上面简单的检查了一下异常是否为Access Violation,事实上,Windows会产生很多的异常,常见的有数组越界,除数为0,数据移出,堆栈错误,堆栈溢出等,可以在MSDN网页查到:
/en-us/library/aa363082(v=vs.85).aspx
注意在catch中的代码要当心,否则会异常嵌套,第二次异常Windows可能会将其认为是不可挽回的异常,因此还是会将你的程序结束。
解决try-catch 在RELEASE版无法捕捉错误
问题: try-catch 在RE LE ASE版无法捕捉错误,而DE BUG可以。
答案:这个跟C++的try-catch异常捕获的两种模式有关。
同步模式和异步模式。
其中前者不能捕获内存访问错误,后者可以捕获内存访问错误。
/EHs是启用同步模式。
(同 /GX)
/EHa是起用异步模式。
要在Release版本使用异步模式,需要加上/E ha选项,此时可以捕获到楼主的异常。
顺便贴写cl的编译参数
-优化-
/O1 最小化空间 minimize space
/Op[-] 改善浮点数一致性 improve floating-pt consistency
/O2 最大化速度 maximize speed
/Os 优选代码空间 favor code space
/Oa 假设没有别名 assume no aliasing
/Ot 优选代码速度 favor code speed
/Ob 内联展开(默认 n=0) inline expansion (default n=0)
/O w假设交叉函数别名 assume cross-function aliasing
/Od 禁用优化(默认值) disable optimizations (default)
/Ox 最大化选项。
(/Ogityb2 /G s) maximum opts. (/Ogityb1 /Gs)
/Og 启用全局优化 enable global optimization
/Oy[-] 启用框架指针省略 enable frame pointer omission
/Oi 启用内建函数 enable intrinsic functions
-代码生成-
/G3 为 80386 进行优化 optimize for 80386
/G4 为 80486 进行优化 optimize for 80486
/GR[-] 启用 C++ RTTI enable C++ RTTI
/G5 为 P entium 进行优化 optimize for P entium
/G6 为 P entium P ro 进行优化 optimize for P entium P ro
/GX[-] 启用 C++ 异常处理(与 /E Hsc 相同) enable C++ EH (same as /E Hsc)
/EHs 启用同步 C++ 异常处理 enable synchronous C++ EH
/GD 为 Windows DLL 进行优化 optimize for Windows DLL
/GB 为混合模型进行优化(默认) optimize for blended model (default)
/EHa 启用异步 C++ 异常处理 enable asynchronous C++ EH
/Gd __cdecl 调用约定 __cdecl calling convention
/EHc extern“C”默认为 nothrow extern "C" defaults to nothrow
/Gr __fastcall 调用约定 __fastcall calling convention
/Gi[-] 启用增量编译 enable incremental compilation
/Gz __stdcall 调用约定 __stdcall calling convention
/Gm[-] 启用最小重新生成 enable minimal rebuild
/GA 为 Windows 应用程序进行优化 optimize for Windows Application
/Gf 启用字符串池 enable string pooling
/QIfdiv[-] 启用 P entium FDIV 修复 enable P entium FDIV fi x
/GF 启用只读字符串池 enable read-only string pooling
/QI0f[-] 启用 P entium 0x0f 修复 enable P entium 0x0f fi x
/Gy 分隔链接器函数 separate functions for linker
/GZ 启用运行时调试检查 enable runtime debug check s
/Gh 启用钩子函数调用 enable hook function call
/Ge 对所有函数强制堆栈检查 force stack checking for all funcs
/Gs[num] 禁用堆栈检查调用 di s able stack checking calls
-输出文件-
/Fa[file] 命名程序集列表文件 name assembly listing file
/Fo 命名对象文件 name object file
/FA[sc] 配置程序集列表 configure assembly listing
/Fp 命名预编译头文件 name precompiled header file
/Fd[file] 命名 .P DB 文件 name .PDB file
/Fr[file] 命名源浏览器文件 name source browser file
/Fe 命名可执行文件 name executable file
/FR[file] 命名扩展 .SBR 文件 name extended .SBR file
/Fm[file] 命名映射文件 name map file
-预处理器-
/FI 命名强制包含文件 name forced include file
/C 不吸取注释 don't strip comments
/U 移除预定义宏 remove predefined macro
/D{=|#} 定义宏 define macro
/u 移除所有预定义宏 remove all predefined macros
/E将预处理定向到标准输出 preprocess to stdout
/I 添加到包含文件的搜索路径 add to include search path
/EP将预处理定向到标准输出,不要带行号 preprocess to stdout, no #line /X 忽略“标准位置” ignore "standard places"
/P预处理到文件 preprocess to file
-语言-
/Zi 启用调试信息 enable debugging information
/Zl 忽略 .OBJ 中的默认库名 omit default library name in .OBJ
/ZI 启用调试信息的“编辑并继续”功能 enable E dit and Continue debug info /Zg 生成函数原型 generate function prototypes
/Z7 启用旧式调试信息 enable old-style debug info
/Zs 只进行语法检查 syntax check only
/Zd 仅要行号调试信息 line number debugging info only
/vd{0|1} 禁用/启用 vtordisp disable/enable vtordisp
/Zp[n] 在 n 字节边界上包装结构 pack structs on n-byte boundary
/vm 指向成员的指针类型 type of pointers to members
/Za 禁用扩展(暗指 /Op) disable extensions (implies /Op)
/noBool 禁用“bool”关键字 di s able "bool" keyword
/Ze 启用扩展(默认) enable extensions (default)
- 杂项 -
/?, /help 打印此帮助消息 print this help message
/c 只编译,不链接 compile only, no link
/W 设置警告等级(默认 n=1) set warning level (default n=1)
/H 最大化外部名称长度 max external name length
/J 默认 char 类型是 unsigned default char type is unsigned
/nologo 取消显示版权消息 suppress copyright message
/WX 将警告视为错误 treat warnings as errors
/Tc 将文件编译为 .c compile file as .c
/Yc[file] 创建 .P CH 文件 create .P CH file
/Tp 将文件编译为 .cpp compile file as .cpp
/Yd 将调试信息放在每个 .OBJ 中 put debug info in every .OBJ
/TC 将所有文件编译为 .c compile all files as .c
/TP将所有文件编译为 .cpp compile all files as .cpp
/Yu[file] 使用 .P CH 文件 use .PCH file
/V 设置版本字符串 set version string
/YX[file] 自动的 .P CH 文件 automatic .PCH
/w禁用所有警告 di s able all w arnings
/Zm 最大内存分配(默认为 %) max memory alloc (% of default)
-链接-
/MD 与 MSVCRT.LIB 链接 link w ith MSVCRT.LIB
/MDd 与 MSVCRTD.LIB 调试库链接 link w ith MSVCRTD.LIB debug lib /ML 与 LIBC.LIB 链接 link w ith LIBC.LIB
/MLd 与 LIBCD.LIB 调试库链接 link w ith LIBCD.LIB debug lib
/MT 与 LIBCMT.LIB 链接 link w ith LIBCMT.LIB
/MTd 与 LIBCMTD.LIB 调试库链接 link w ith LIBCMTD.LIB debug lib /LD 创建 .DLL Create .DLL
/F 设置堆栈大小 set stack size
/LDd 创建 .DLL 调试库 Create .DLL debug libary
/link [链接器选项和库] [linker options and libraries]。