一、 引言
本文主要介绍以下几方面内容:
常见编译错误VC调试器
VC快捷键
VC项目文件说明
环境参数的设置
二、常见编译错误
这一般是由于使用了参数/Yu“stdafx.h”,意思是在每个文件中都应该使用#include来包含这个头文件。一般改正,就是在每个CPP文件中包含这个文件就可以。
一是所引用的函数、变量不存在、拼写不正确或者使用错误;
其次可能使用了不同版本的连接库。
三、VC调试器
1. 调试环境的建立
在VC中每当建立一个工程(Project)时,VC会为你建立两个版本,Release版本,和Debug版本(默认)。
Release版本是当程序完成后,准备发行时用来编译的版本;
Debug版本是用在开发过程中进行调试时所用的版本。
Debug 版本当中,包含着Microsoft格式的调试信息,不进行任何代码优化,而在Release版本对可执行程序的二进制代码进行了优化,其中不包含任何的调试信息。
在新建立的工程中,你所看到是Debug版本,若要选择Release版本,可以选择菜单Project中的Setting命令,这时屏幕上面弹出Project Setting对话框,在Setting For下拉列表中选择Release。
vc 图
vs2005 图
2. 断点(breakpoint)
分类:在VC中,你可以设置多种类型的断点,我们可以根据断点的性质把断点分为三类:
(1)与位置有关的断点(F9)
1) 与位置有关的逻辑断点——到点条件成立才断
有的时候你可能并不需要程序每次运行到这儿都停下来,而是在满足一定条件的情况下才停下来,这时你就需要设置一种与位置有关的逻辑断点。要设置这种断点我们只需要在Edit中选中Breakpoint项,则弹出Breakpoint对话框,选其中的Location标签,在Location页面中单击Condition按钮,在Expression编辑框中写出你的逻辑表达式,如X>=3或a+b>25,最后按OK返回。这种断点主要是由其位置发生作用的,但也结合了逻辑条件,使之更灵活。如图:
2) 在在汇编代码上设立断点:
(2)与逻辑条件有关的断点;
– 选中Breakpoint对话框中的DATA标签;– DATA页面中的Expression编辑框中写出你的逻辑表达式,如(6==sum);
– 选中Breakpoint对话框中的DATA标签;– 在Expression编辑框中写出你需要监视的表达式;
– 选中Breakpoint对话框中的DATA标签;– 在Expression编辑框中写出你需要监视数组名;– 在Number of Elements 编辑框输入你需要监视数组元素的个数;
– 选中Breakpoint对话框中的DATA标签;– 在Expression编辑框中输入形如*pointname,其中*pointname为指针变量名;– 在Number of Elements 编辑框输入你需要监视数组元素的个数;
– 选中Breakpoint对话框中的DATA标签;– 在Expression编辑框中输入变量名;– 点击在Expression编辑框的右边的下拉键头;– 选取Advanced选项,这时Advanced Breakpoint 对话框出现;– 在context框中输入对应的函数名和(如果需要的话)文件名;
(3)与WINDOWS消息有关的断点;
– 选中Breakpoint对话框中的Message标签;– 在Break At WndProc 编辑框中输入Windows 函数的名称;– 在Set One Breakpoint From Each Message To Watch下拉列表框中选择对应的消息;
应用断点:如何控制程序的运行
当我们从菜单Build到子菜单Start Debuging 选择Go 程序开始运行在Debug状态下,程序会由于断点而停顿下来后,可以看到有一个小箭头,它指向即将执行的代码。随后,我们就可以按要求来控制程序的运行:其中有四条命令:Step over, step Into , Step Out ,Run to Cursor 。
Step over 的功能是运行当前箭头指向的代码(只运行一条代码)。F10
Step Into的功能是如果当前箭头所指的代码是一个函数的调用,则用Step Into 进入该函数进行单步执行。F11
Step Out的功能是如当前箭头所指向的代码是在某一函数内,用它使程序运行至函数返回处。Shift F11
Run to Cursor的功能是使程序运行至光标所指的代码处。Ctrl F10
3. VC调试器——查勘现场
先看一下这张图,然后再看下面的介绍:
(1) 弹出式调试信息泡泡(Data Tips Pop_up Information)
(2)变量窗口(VARIABLE WINDOW)——看程序中的变量
(3)观察窗口(WATCH WINDOW)——索要变量或表达式的当前值
(4)快速查看变量对话框(quick watch)
1)在Debug 菜单,选择Quick Watch命令,这时屏幕上将会出现Quick Watch 对话框;2)在Expression 编辑框中输入变量名,按回车;3)在Current Value 格子中将出现变量名及其当前对应的值;4)如要改变该变量的值只需双击该变量对应的Name 栏,输入你要改变的值;5)如要把该变量加入到观察窗口中,点击Add watch 按钮;6)点击Close 按钮返回;
Shift F9 如图:
(5)查看内存中的值
(6)查看或改变CPU寄存器中的值
OV是溢出标志UP是方向标志EI是中断使能标志Sign 是符号标志Zero是零标志Parity是奇偶较验标志Carry 是进位标志
(7)查看Call Stack
(8)查看Disassembly窗口
四、VC快捷键
1. VC编辑快捷键
按下Alt 键不放,点击鼠标左键拖动,可以选择文本块、可选择列;
按着Ctrl键不放,单击一个单词,可以选择一个单词,或双击;
将光标移在开始位置,按住shift点击鼠标左键可选择一段(在IE浏览其中照样可用,看不到光标而已);
双击鼠标左键可选择一个单词;
按住shift+上下方向键可选择行;
按住ctrl+shift+左右方向键可选择一个单词;
按Ctrl+C可COPY光标所在的这一行;
按住shift+[End]可选择本行;
F3 向下
Tab 选择的行全部右移一个 TAB键的宽度
Alt + F8 按定义的格式重新排列选定的文本。
shift + F3 向上
shift + Tab 选择的行全部左移一个 TAB键的宽度
Ctrl + F 查找、搜索
Ctrl + H 替换
Ctrl + G 到某行
Ctrl + U 选择部分变为小写
Ctrl + shift + U 选择部分变为大写
Ctrl+J 向上搜索最近的#if/#else/#ifdef/#endif
Ctrl+K 向下搜索最近的#if/#else/#ifdef/#endif
Ctrl+] 自动配对大括号或小括号。但有时不对应,是因为其他字符有“{”或“}”存在
2. VC调试快捷键
F5 Go 运行碰到断点就停
F7 Build 编译链接
F9 Add/Remove Breakpoint 插入/删除断点
F10 Step Over 一步步运行,碰到函数不进去
F11 Step Into 一步步运行,碰到函数就进去(当然那些WinAPI由于在Dll中,就进不去了!)
Ctrl + F5 Execute Program 运行
Ctrl + F7 Compile 编译一个源文件
Ctrl + F10 Run to Cursor 调试到光标所在位置
Shift + F5 Stop Debugging 停止调试
Shift + F9 Quick Watch 快速查看/修改变量信息
Shift + F11 Step Out 从当前函数中跳出
Alt + F9 Breakpoint 高级断点设置
Alt + 7 Call Stack 堆栈窗口,可以察看函数调用情况
Alt + 4 Variables 当前运行代码行的变量或者返回值信息
Alt + 3 Watch 可以把关注的变量拖入窗口中,察看/修改变量信息。
五、VC项目文件说明
.opt工程关于开发环境的参数文件,如工具条位置等信息;
.dsp(DeveloperStudio Project)项目文件,文本格式,项目参数配置文件,不熟悉的话不要手工修改;
.dsw(DeveloperStudio Workspace)是工作区文件,其他特点和dsp差不多,可以由.dsp生成;
.plg是编译信息文件,编译时的error和warning信息文件(实际上是一个html文件),一般用处不大,在Tools->Options里面有个选项可以控制这个文件的生成;
以上是我们工程编译时候最常见的,下边这些可以不用关心,了解就可以了。
.aps(AppStudio File),资源辅助文件,二进制格式,一般不用去管他;
.clw ClassWizard信息文件,实际上是INI文件的格式,有兴趣可以研究一下,有时候ClassWizard出问题,手工修改CLW文件可以解决,如果此文件不存在的话,每次用ClassWizard的时候会提示你是否重建;
.hpj(Help Project)是生成帮助文件的工程,用microsfot Help Compiler可以处理;
.mdp(Microsoft DevStudio Project)是旧版本的项目文件,如果要打开此文件的话,会提示你是否转换成新的DSP格式;
.map是执行文件的映像信息纪录文件,除非对系统底层非常熟悉,这个文件一般用不着;
.pch(Pre-Compiled File)是预编译文件,可以加快编译速度,但是文件非常大;
.pdb(Program Database)记录了程序有关的一些数据和调试信息,在调试的时候可能有用;
.exp只有在编译DLL的时候才会生成,记录了DLL文件中的一些信息,一般也没什么用;
注:如果你想与别人共享你的源代码项目,但是把整个项目做拷贝又太大。你完全可以删掉以下文件:
.dsw、.ncb、.opt、.aps、.clw、. plg文件以及Debug、Release目录下的所有文件
六、环境参数的设置(Project Setting —> Alt F7)
Warning level
|
控制警告信息,其中Level1是最严重的级别
| ||
Warnings as errors
|
将警告信息当作错误处理
| ||
Optimizations
|
代码优化,可以在Category的Optimizations项中进行更细的设置
| ||
Generate browse info
|
用以生成.sbr文件,记录类、变量等符号信息,可以在Category的Listing Files项中进行更多的设置
| ||
Debug info
|
生成调试信息
|
None
|
不产生任何调试信息(编译比较快)
|
Line Numbers Only
|
仅生成全局的和外部符号的调试信息到.OBJ文件或.EXE文件,减小目标文件的尺寸
| ||
C7 Compatible
|
记录调试器用到的所有符号信息到.OBJ文件和.EXE文件
| ||
Program Database
|
创建.PDB文件记录所有调试信息
| ||
Program Database for Edit and Continue
|
创建.PDB文件记录所有调试信息,并且支持调试时编辑
|
pointer_to_member representation
|
用来设置类定义/引用的先后关系,一般为Best-Case Always表示在引用类之前该类肯定已经定义了
|
Enable Exception Handling
|
进行同步的异常处理
|
Enable Run-Time Type Information
|
迫使编译器增加代码在运行时进行对象类型检查
|
Disable Construction Displacements
|
设置类构造/析构函数调用虚函数问题
|
Processor
|
表示代码指令优化,可以为80386、80486、Pentium、Pentium Pro,或者Blend表示混合以上各种优化
|
|
|
Use run-time library
|
用以指定程序运行时使用的运行时库(单线程或多线程,Debug版本或Release版本),有一个原则就是,一个进程不要同时使用几个版本的运行时库,连接了单线程库就不支持多线程调用,连接了多线程库就要求创建多线程的应用程序
|
Single-Threaded
|
静态连接LIBC.LIB库
|
Debug Single-Threaded
|
静态连接LIBCD.LIB库
| ||
Multithreaded
|
静态连接LIBCMT.LIB库
| ||
Debug Multithreaded
|
静态连接LIBCMTD.LIB库
| ||
Multithreaded DLL
|
动态连接MSVCRT.DLL库
| ||
Debug Multithreaded DLL
|
动态连接MSVCRTD.DLL库
| ||
Calling convention
|
用来设定调用约定,有三种:__cdecl、__fastcall和__stdcall。各种调用约定的主要区别在于,函数调用时,函数的参数是从左到右压入堆栈还是从右到左压入堆栈;在函数返回时,由函数的调用者来清理压入堆栈的参数还是由函数本身来清理;以及在编译时对函数名进行的命名修饰(可以通过Listing Files看到各种命名修饰方式)
| ||
Struct member alignment
|
用以指定数据结构中的成员变量在内存中是按几字节对齐的,根据计算机数据总线的位数,不同的对齐方式存取数据的速度不一样。这个参数对数据包网络传输等应用尤为重要,不是存取速度问题,而是数据位的精确定义问题,一般在程序中使用#pragma pack来指定
|
Disable Language Extensions
|
表示不使用微软为标准C做的语言扩展
|
Eliminate Duplicate Strings
|
主要用于字符串优化(将字符串放到缓充池里以节省空间),使用这个参数,使得
char *sBuffer = "This is a character buffer";
char *tBuffer = "This is a character buffer";
sBuffer和tBuffer指向的是同一块内存空间
|
Enable Function-Level Linking
|
告诉编译器将各个函数按打包格式编译
|
Enables minimal rebuild
|
通过保存关联信息到.IDB文件,使编译器只对最新类定义改动过的源文件进行重编译,提高编译速度
|
Enable Incremental Compilation
|
同样通过.IDB文件保存的信息,只重编译最新改动过的函数
|
Suppress Startup Banner and Information Messages
|
用以控制参数是否在output窗口输出
|
Generate browse info
|
上面已经提到过,这里可以进行更多的设置
| ||
Exclude Local Variables from Browse Info
|
是否将局部变量的信息放到.SBR文件中
| ||
Listing file type
|
可以设置生成的列表信息文件的内容
|
Assembly-Only Listing
|
仅生成汇编代码文件(.ASM扩展名)
|
Assembly With Machine Code
|
生成机器代码和汇编代码文件(.COD扩展名)
| ||
Assembly With Source Code
|
生成源代码和汇编代码文件(.ASM扩展名)
| ||
Assembly, Machine Code, and Source
|
生成机器码、源代码和汇编代码文件(.COD扩展名)
| ||
Listing file name
|
生成的信息文件的路径,一般为Debug或Release目录下,生成的文件名自动取源文件的文件名
|
Maximize Speed
|
生成最快速的代码
| ||
Minimize Size
|
生成最小尺寸的程序
| ||
Customize
|
定制优化
|
Assume No Aliasing
|
不使用别名(提高速度)
|
Assume Aliasing Across Function Calls
|
仅函数内部不使用别名
| ||
Global Optimizations
|
全局优化,比如经常用到的变量使用寄存器保存,或者循环内的计算优化,如
i = -100;while( i < 0 ){i += x + y;} 会被优化为i = -100;t = x + y;
while( i < 0 ){i += t;}
| ||
Generate Intrinsic Functions
|
使用内部函数替换一些函数调用(提高速度)
| ||
Improve Float Consistency
|
浮点运算方面的优化
| ||
Favor Small Code
|
程序(exe或dll)尺寸优化优先于代码速度优化
| ||
Favor Fast Code
|
程序(exe或dll)代码速度优化优先于尺寸优化
| ||
Frame-Pointer Omission
|
不使用帧指针,以提高函数调用速度
| ||
Full Optimization
|
组合了几种参数,以生成最快的程序代码
| ||
Inline function expansion
|
内联函数扩展的三种优化(使用内联可以节省函数调用的开销,加快程序速度)
|
Disable
|
不使用内联
|
Only __inline
|
仅函数定义前有inline或__inline标记使用内联
| ||
Any Suitable
|
除了inline或__inline标记的函数外,编译器“觉得”应该使用内联的函数,都使用内联
|
Generate debug info
|
生成Debug信息到.PDB文件(具体格式可以在Category->Debug中设置)
|
Ignore All Default Libraries
|
放弃所有默认的库连接
|
Link Incrementally
|
通过生成. ILK文件实现递增式连接以提高后续连接速度,但一般这种方式下生成的文件(EXE或DLL)较大
|
Generate Mapfile
|
生成.MAP文件记录模块相关信息
|
Enable Profiling
|
这个参数通常与Generate Mapfile参数同时使用,而且如果产生Debug信息的话,不能用.PDB文件,而且必须用Microsoft Format。
|
(或 wWinMain,必须采用__stdcall调用约定);DLL采用_DllMainCRTStartup调用DllMain函数(必须采用__stdcall调用约定)。
Description: Register COM
Commands: regsvr32 /s /c $(TargetPath)
echo regsvr32 exe.time > $(TargetDir)$(TargetName).trg
Outputs: $(TargetDir)$(TargetName).trg