c程序编译流程

程序的基本流程如图:

1. 预处理

预处理相当于根据预处理指令组装新的C/C++程序。经过预处理,会产生一个没有宏定义,没有条件编译指令,没有特殊符号的输出文件,这个文件的含义同原本的文件无异,只是内容上有所不同。

  • 读取C/C++源程序,对其中的伪指令(以#开头的指令)进行处理

①将所有的“#define”删除,并且展开所有的宏定义

②处理所有的条件编译指令,如:“#if”、“#ifdef”、“#elif”、“#else”、“endif”等。这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉。

③处理“#include”预编译指令,将被包含的文件插入到该预编译指令的位置。

(注意:这个过程可能是递归进行的,也就是说被包含的文件可能还包含其他文件)

  • 删除所有的注释

  • 添加行号和文件名标识。

    以便于编译时编译器产生调试用的行号信息及用于编译时产生的编译错误或警告时能够显示行号

  • 保留所有的#pragma编译器指令

2. 编译

将预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后,产生相应的汇编代码文件。

3. 汇编

将编译完的汇编代码文件翻译成机器指令,并生成可重定位目标程序的.o文件,该文件为二进制文件,字节编码是机器指令。

汇编器是将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。所以汇编器的汇编过程相对于编译器来讲比较简单,它没有复杂的语法,也没有语义,也不需要做指令优化,只是根据汇编指令和机器指令的对照表一一翻译即可。

4. 链接

通过链接器将一个个目标文件(或许还会有库文件)链接在一起生成一个完整的可执行程序。

由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。

例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。

链接程序的主要工作就是将有关的目标文件彼此相连接,也就是将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。

命令行下编译文件

  因为VS自带了开发人员选项,所以我们不需要再去配置环境变量了(感谢微软~)。

  • 在win10中询问Cortana,输入VS,选择VS2015开发人员命令提示。

  • 进入.c或者.cpp文件所在路径,输入命令:cl  *.cpp,编译预先用记事本或者Editplus写好的文件,查看结果
  • 如上图所示,生成了两个文件,一个输出文件:hello.exe,一个obj文件:hello.obj;查看文件夹:

  • 执行.exe文件,查看运行结果,如下图:

说明

在以上的编译过程中我们只用了cl的编译命令就帮我们最终的可执行文件HelloWorld.exe,这是因为cl.exe程序在编译时自己会去调用link.exe、lib.exe等程序。

可通过”cl -help “查看常用的编译选项

选项 作用
/O1 创建小代码
/O2 创建快速代码
/Oa 假设没有别名
/Ob 控制内联展开
/Od 禁用优化
/Og 使用全局优化
/Oi 生成内部函数

更详细的中文介绍也可参考这篇博文: 
http://www.lellansin.com/%E5%BE%AE%E8%BD%AF-cl-exe-%E7%BC%96%E8%AF%91%E5%99%A8.html

静态库

打开VS2015,新建一个项目,选择win32项目,点击确定,选择静态库这个选项,预编译头文件不选。

在这个空项目中,添加一个.h文件和4个.cpp文件。名字我们起为head.h和add.cpp,div.cpp,mul.cpp,sub.cpp

head.h文件:

add.cpp:

#include"head.h"
int add(int a, int b)
{
return a + b;
}

div.cpp:

#include"head.h"
double div(int a, int b)
{
return (a + 0.0) / (b + 0.0);
}

mul.cpp:

#include"head.h"
int mul(int a,int b)
{
return a*b;
}

sub.cpp:

#include"head.h"
int sub(int a, int b)
{
return a - b;
}


编译这个项目之后(生成——》生成解决方案),会在debug文件夹下生成mymath.lib文件,这个就是我们需要的静态链接库。

下面说明如何调用静态链接库。

  • 首先需要新建一个空项目,起名为test_mymath。
  • 将之前static项目下的head.h这个文件复制到mymath项目的目录下

  • 在工程中加入head.h文件,快捷键:Ctrl + Alt +A添加现有项:

  

新建一个20145211hzy.cpp文件如下:


编译运行可得结果:

#pragma comment(lib,"mymath.lib"),这一句是显式的导入静态链接库。除此之外,还有其他的方法,比如通过设置路径等等,这里不做介绍。

或者 选中工程名,点击右键 -> 属性, 在“ VC++目录 ”的包含目录里面加入head.h的所在目录的路径,库目录里面加入mymath.lib所在目录的路径;在链接器->输入->附加依赖项输入“mymath.lib”。然后源文件里添加#include"head.h"就OK了。

动态库

  • 创建DLL
1.新建一个空白工程;
2.项目菜单->属性->配置属性->常规->配置类型,改为动态库(.dll)

3.添加DLL.h,DLL.cpp;
4.在dll.h中添加代码

#ifdef DLL_API

#else

#define DLL_API _declspec(dllimport)

#endif

DLL_API int add(int a, int b);

 DLL_API sub add(int a, int b);
DLL_API div add(int a, int b);
DLL_API mul add(int a, int b);
5.在DLL.cpp中添加代码

#include "dll.h"

#define DLL_API _declspec(dllexport)

int add(int a, int b)

{

return a + b;

}

double div(int a, int b)
{
return (a + 0.0) / (b + 0.0);
}

int mul(int a,int b)
{
return a*b;
}

int sub(int a, int b)
{
return a - b;
}

6.编译

  • 调用DLL

1.在该解决方案中新建一个win32控制台项目;

2.在新项目上单击右键,设为启动项;

3.再次在新项目上单击右键->添加->引用->项目->解决方案,将DLL项目前边的方框选中。

4.添加代码:

#include "stdafx.h"

_declspec(dllexport) int add(int a, int b);

_declspec(dllexport) int sub(int a, int b);

_declspec(dllexport) int MUL(int a, int b);

_declspec(dllexport) double div(int a, int b);

int main()

{

int a=3, b=4;
printf("%d\n", add(a,b));
printf("%d\n", sub(a,b));
printf("%lf\n", divs(a, b));
printf("%d\n", mul(a, b));
system("pause");

return 0;

}

5.编译完成。

  • 其他

如果创建与调用不在同一个解决方案内,需要将生成的mymath.lib文件复制到win32项目文件夹中,并添加引用命令:

#pragma comment(lib,"mymath.lib"),或者在项目->属性->VC++目录中手动添加;

再将mymath.dll文件放入win32项目的调试文件夹中。

关于调试

调试是VS2015很强大的一项功能,它可以帮我们找到程序中的很多错误。

开始调试

先贴出我的测试代码(需要说明的是,这段代码并没有问题):

#include <stdio.h>
#include"windows.h"

int sum(int m);

int main()
{
int * pi;
int i, n = 0;
pi = &i;
int arr[3] = { 10, 20, 30 };
pi = arr;
sum(50);
for (i = 0; i <= 50; i++)
{
n += i;
}

printf("The sum of 1-50 is %d \n", n);
system("pause");
}

int sum(int m)
{
int i, n = 0;
for (i = 1; i <= m; i++)
{
n += i;
}

printf("The sum of 1-50 is %d \n", n);
return n;
}

1. 设置断点:可以直接在你需要设置断点的地方按F9,或者在那行右键->断点->插入断点(下面会介绍如何设置函数、临时、条件断点);双击红点,撤销断点。

 

2. 调试:逐过程调试:按F10,或者点击菜单栏的调试–>逐过程;

       逐语句调试:按F11,或者点击菜单栏的调试–>逐语句

函数断点

  •   在main处设置断点,逐过程调试,因为在main处设置了断点,main函数还未执行

  • 继续按F10,直到运行完毕

两个断点间的调试(关于函数断点的逐过程和逐语句):

  在调试过程中F5是执行到下一个断点。F10是逐过程,与逐语句不同的是,在执行到下图中断点时,再执行会执行断点下面的语句,而不是去执行语句中的方法。

而F11是逐语句,在执行到下图中的断点 时,按F11会执行到sum里面逐步记录执行过程。

条件断点:

  设置条件断点非常容易。在特定的行上,按F9设置断点;然后右击断点–编辑窗口左侧的红点,在上下文菜单上选择“条件”。

现在我再运行这个程序按F5达到条件断点,只有当x等于5时,程序运行才会被中断。对于其它条件下的x值,断点将被跳过。

3. 完毕

Alt+F4强行退出调试:

3相关快捷键总结:

F6: 生成解决方案
Ctrl+F6: 生成当前项目
F7: 查看代码
Shift+F7: 查看窗体设计器
F5: 启动调试
Ctrl+F5: 开始执行(不调试)
Alt+F4: 停止调试
Ctrl+Shift+F5: 重启调试
F9: 切换断点
Ctrl+F9: 启用/停止断点
Ctrl+Shift+F9: 删除全部断点
F10: 逐过程
Ctrl+F10: 运行到光标处
F11: 逐语句

总结

VS2015是一个非常好的软件,我今天分享的知识冰山一角,可以做的还有很多!

VS2015——命令行下编译、静态库动态库制作以及断点调试的更多相关文章

  1. c# 命令行下编译c#文件 // c# file类读写文件

    c# 命令行下编译c#文件 2010-03-01 15:02:14|  分类: c# 学习|字号 订阅     在 开始  ——>程序 ——>vstool中打开vs2008命令提示. 通过 ...

  2. JNI之——在cmd命令行下编译执行C/C++源文件

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46604269 一直用java来敲代码,java配置好jre路径之后.在cmd下编译 ...

  3. Linux命令行下编译Android NDK的示例代码

    这几天琢磨写一个Android的Runtime用来加速HTML5 Canvas,让GameBuilder+CanTK 不但开发速度快,运行速度也能接近原生应用.所以花了点时间研究 Android ND ...

  4. Linux下编译tinyxml生成动态库

    首先去到sourceforge下载tinyxml的源码,https://sourceforge.net/projects/tinyxml/?source=dlp,最新版本是2.6.2. 将下载成功的t ...

  5. CMD命令行下编译.Net Visual Studio 项目

    有时候我们需要编译.net 的sln解决方案,可是VS打开的速度太慢,可以用命令行进行代替,详细过程如下: 1.开始菜单——>Visual Studio 2017(根据你电脑上安装的VS版本来) ...

  6. hadoop——在命令行下编译并运行map-reduce程序 2

     hadoop map-reduce程序的编译需要依赖hadoop的jar包,我尝试javac编译map-reduce时指定-classpath的包路径,但无奈hadoop的jar分布太散乱,根据自己 ...

  7. 命令行下编译Wordcount

    1. 编辑WordCount.java文件,在下载的hadoop安装包里有WordCount的例子 http://mirrors.hust.edu.cn/apache/hadoop/common/ha ...

  8. C/C++ 跨平台交叉编译、静态库/动态库编译、MinGW、Cygwin、CodeBlocks使用原理及链接参数选项

    目录 . 引言 . 交叉编译 . Cygwin简介 . 静态库编译及使用 . 动态库编译及使用 . MinGW简介 . CodeBlocks简介 0. 引言 UNIX是一个注册商标,是要满足一大堆条件 ...

  9. gcc编译工具生成动态库和静态库之一----介绍

     1.库的分类 根据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. ...

随机推荐

  1. POJ1815 Friendship(字典序最小最小割割边集)

    看了题解.当时也觉得用邻接矩阵挺好写的,直接memset:然而邻接矩阵不懂得改,于是就放开那个模板,写了Dinic.. 方法是,按字典序枚举每一条满流的边,然后令其容量减1,如果最大流改变了,这条边就 ...

  2. fragment中嵌入viewpager的问题

    今天终于解决了这个问题 原来问题是出现于viewpager在这里的layout_height不能设置为"wrap_content" 之前我遇到空白的问题,我还以为是管理的问题 所以 ...

  3. 完数[HDU1406]

    完数 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission( ...

  4. Codeforces Round #366 Div.2[11110]

    这次出的题貌似有点难啊,Div.1的Standing是这样的,可以看到这位全站排名前10的W4大神也只过了AB两道题. A:http://codeforces.com/contest/705/prob ...

  5. BZOJ3723 : PA2014Final Gra w podwajanie

    暴力搜索出所有可行的形状,可以发现本质不同的形状数只有6000个左右. 对于每个形状,它的大小不超过$8\times 8$,故可以按照右下角为原点重建坐标系,用一个unsigned long long ...

  6. mysql 的 find_in_set函数使用方法

    举个例子来说: 有个文章表里面有个type字段,他存储的是文章类型,有 1头条,2推荐,3热点,4图文 .....11,12,13等等 现在有篇文章他既是 头条,又是热点,还是图文, type中以 1 ...

  7. Facebook React.js库 入门实例教程

    作者: 阮一峰 日期: 2015年3月31日 现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩 ...

  8. 【ZOJ】1015 Fishing Net

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1015 题意:给出一个n个点的无向图,询问是否为弦图,弦图定义为对于图中任意 ...

  9. AIX日常维护

    1  /etc/security/limits与limit命令 AIX 5.3上 下面是文件/etc/security/limits文件里面有关软限制和硬限制的部分. * * Sizes are in ...

  10. MyBatis的几种批量操作

    MyBatis中批量插入 方法一: <insert id="insertbatch" parameterType="java.util.List"> ...