为什么要对C源程序进行编译与链接的区别、链接

提示:电脑技术网上次更新了
,现在小编邀请大家一起来阅读
有很多网友问“你好,C++(4)2.1.3 我的父亲母亲:编译器和链接器 2.1.4 C++程序执行背后的故事 - 你好,C++”相关的问题,整理了“你好,C++(4)2.1.3 我的父亲母亲:编译器和链接器 2.1.4 C++程序执行背后的故事 - 你好,C++”相关的解决方案,大多数用户都有:请问你好,C++(4)2.1.3 我的父亲母亲:编译器和链接器 2.1.4 C++程序执行背后的故事 - 你好,C++这样的问题,如下就是整理的帖子内容:
2.1.3& 我的父亲母亲:编译器和链接器
从表面上看,我是由Visual Studio创建的,而实际上,真正负责编译源代码创建生成可执行程序HelloWorld.exe的却是Visual Studio中集成的C++编译器cl.exe和链接器link.exe。他们二老,才是我的亲生爹妈。
为了便于人们的编写、阅读和维护,我们的源文件是使用C++这种人们可以理解的高级程序设计语言编写的。然而,计算机却并不理解这种高级语言,也就无法直接执行高级语言编写而成的源文件。所以,这里就需要一个翻译的工作,将源文件中人们可以理解的C++高级语言翻译成机器可以理解执行的机器语言。我老爸编译器实际上是个翻译官,他的工作就是将用C++这种高级语言编写的源文件(.cpp)翻译成用计算机可以看懂的机器语言表示的目标文件(.obj),大家通常将这一过程称为编译。
在Visual Studio中,我老爸的名字是cl.exe,大家可以在开始菜单中找到“VS2012 开发人员命令提示”,然后在打开的DOS窗口中通过cl命令请他老人家出手,将一个cpp源文件编译成相应的obj目标文件。比如,要想让我爸将我的源文件HelloWorld.cpp编译成对应的目标文件HelloWorld.obj,可以使用下面的命令:
cl /c /EHsc HelloWorld.cpp
其中,cl是调用编译器的指令,其后的选项用于指定编译器的编译行为。这里的“/c”表示只编译不链接;“/EHsc”指定编译器使用何种异常处理模型;最后一个选项HelloWorld.cpp则是即将要编译的C++源文件。源文件HelloWorld.cpp经过我爸编译器的编译后,得到的还只是一个无法直接执行的目标文件HelloWorld.obj,还需要我妈链接器将这个目标文件和Visual C++所提供的标准库目标文件(比如,libcpmt.lib)整合成最终的可执行文件(从标准库目标文件中查找程序目标文件所用到的外部函数等符号,然后填写到程序目标文件以生成最终的可执行文件),这一过程就被称之为链接。在“VS2012 开发人员命令提示”中,大家可以用如下的命令请我妈链接器link.exe来完成这一链接过程:
link HelloWorld.obj
当然,整个编译链接的工作,也可以由我爸编译器cl.exe一个人完成:
cl /EHsc HelloWorld.cpp
经过我爸我妈的编译链接过程,我从一个源文件(HelloWorld.cpp)变成了一个可执行文件(HelloWorld.exe),我就这样哇哇坠地了。整个过程,如图2-6所示:
图2-6 编译链接过程
2.1.4& C++程序的执行过程
一旦生成可执行文件,就可以给操作系统下达指令让文件开始执行。一个程序的执行是从其主函数开始的。但是在进入主函数开始执行之前,操作系统会帮我们做很多准备工作。比如,当操作系统接到执行某个程序的指令后,它首先要创建相应的进程并分配私有的进程空间;然后加载器会把可执行文件的数据段和代码段映射到进程的虚拟内存空间中;操作系统接着会初始化程序中定义的全局变量等。做好这些准备工作,程序就可以进入主函数开始执行了。
进入主函数后,程序会按照源代码给我制定的人生规划,一条语句一条语句地往下执行,一步一步地往下走。大家一定还记得,我的源代码是这样的:
int main()
// 在屏幕上输出“Hello World!”字符串
从这里可以看到,进入主函数后,我的第一条语句就是:
这条语句的意思是让我在DOS窗口中显示“Hello World!”这样一串文字,于是我便开始控制DOS窗口,在其中显示这串文字,完成程序员通过这行代码交给我的任务。
接下来的一条语句是:
这条简短的语句宣告了我人生历程的结束。它表示主函数的结束,整个程序执行完毕。图2-7所示的是我短暂而光辉的一生!
图2-7& Hello World程序短暂而光辉的一生
知道更多:C++程序执行背后的故事
在上面的例子中,我们看到一个C++程序的执行过程,是从main()函数开始逐条语句往下执行的。这个过程看起来非常简单,但在每条语句的背后,都还有着更多的故事。
在Visual Studio调试模式下的反汇编视图(在调试模式下通过Alt+8快捷键打开)中,我们可以看到C++程序中的各条语句所对应的汇编代码。这下,程序中各条语句做了什么事情、各个功能是如何实现的,都一目了然了。HelloWorld程序虽然只是简单地输出一个字符串,但是当我们把这个程序拆解开,却可以发现它背后做了很多事情。在汇编视图下的HelloWorld程序如下(汇编代码太长,我们只保留其中的关键操作):
#include &iostream&
using namespace
int main()
// 完成准备工作
rep stos dword ptr es:[edi]
// 完成任务
// 在屏幕输出“Hello World!”字符串
eax,dword ptr ds:[00DD031Ch]
ecx,dword ptr ds:[0DD0318h]
// 调用标准库中的操作符来完成任务
std::operator&&&std::char_traits&char& & (0DC12A3h)
dword ptr ds:[0DD0324h]
__RTC_CheckEsp (0DC132Ah)
当我们启动一个程序后,操作系统会创建一个新的进程来执行这个程序。所谓进程,就是应用程序的一个实例。操作系统创建进程的时候,会为其分配一定的内存空间(默认堆),作为其私有的虚拟地址空间。通常,一个应用程序的执行对应于一个进程,进程负责管理这个程序运行时的一切事物,例如资源的分配与调度等等。但是,作为程序执行的调度者,它并不负责程序的执行,具体的执行工作,则是由它所创建的线程来完成的。每个进程都有一个主线程,如果是多线程应用程序,还可以有多个辅助线程。线程并不拥有资源(它使用的是它所属进程的资源),但是它拥有自己的执行入口、执行的顺序系列和一个执行终点。
在这里,当负责执行这个程序的主线程被创建以后,它就会进入main()函数开始执行。它首先会执行一些初始化工作,例如保存现场环境、对堆进行初始化以及完成程序参数的传递等等,然后才是执行具体的程序代码。虽然C++程序代码只有一行,但是在汇编视图下,却被分解成了多个步骤来完成。主函数的执行,也不过是对于一些寄存器的操作和对库函数的调用而已。例如,在main()函数的第一句就是用“push ebp”保存当前地址(在汇编代码中,ebp代表了当前地址)。这里我们一定会感到奇怪,为什么在进入main()函数后的第一件事不是在C++程序代码中看到的输出一个字符串,而是保存当前地址呢?实际上,我们从程序代码中所看到的只是我们对于要实现的功能的描述,而真正地要实现这些功能,C++程序还要在背后为我们完成很多事情。这里的“push ebp”保存当前地址,就是为了让这个main()函数在执行完毕后,可以顺利返回原来的地址继续往下执行。除了对于寄存器的操作(push、mov以及pop等汇编指令)之外,汇编代码中更重要的是通过“call”指令完成的对其他函数的调用。例如,“call &__RTC_CheckEsp (0DC132Ah)”这个call指令就是调用__RTC_CheckEsp()函数(由编译器在调试版本中添加)在程序执行完毕后检查堆栈是否平衡。
在汇编视图下,我们可以看到每一条C++语句后面都有故事。只有了解了每一条语句背后的故事,才能真正地理解这一条语句。这同样也告诉我们,如果我们发现某条语句的行为出现了异常而我们又无法从代码层面找到原因,我们就需要从这条语句的背后寻找真正的原因。
2.1.5& 程序的两大任务:描述数据与处理数据
人们编写程序的目的,是为了用程序解决现实世界中的问题。人们观察发现,所有这些问题都是以数据作为输入,然后对这些数据进行处理,最后获得结果数据而使问题得到解决的。所以,既然我是用来帮助人们解决问题的,那么我的任务自然也就离不开对数据的描述和对数据的处理。如图2-8所示。
人们用公式给我下了一个定义:
数据 + 算法 = 程序
其中,数据可以看成是对现实世界中的各个事物的抽象和描述。例如,在C++程序中,我们将现实世界中的各种数据抽象成各种数据类型,比如我们将整数抽象成int类幸,将小数抽象成double类型等。然后反过来用这些类型定义的变量来描述我们在生活中遇到的某个具体的数据。比如,用int类型定义的变量nWidth来描述某个矩形的宽度;用string类型定义的变量strName来描述某个人的名字;我们甚至还可以创建自定义的数据类型来描述更加复杂的事物,比如我们可以创建一个Human数据类型来抽象“人”这个复杂事物,然后用它定义一个变量来描述某个具体的人。总之,用数据对现实世界中的事物进行抽象和描述,是我的第一个任务。
图2-8& 我的人生目的
用数据对现实世界进行描述并不是我的最终目的,我的最终目的是对这些数据进行处理,从而获得想要的结果数据。比如,我们用nWidth和nHeight描述了一个矩形的宽和高,然而,这并不是我们想要的结果数据,我们想要的是矩形的面积。所以,我们还必须对nWidth和nHeight这两个数据进行处理,用“*”符号计算两个数的乘积,才能获得我们想要的矩形面积。对数据处理过程的抽象,人们称之为算法。而我的第二个任务,就是描述和表达算法,对数据进行处理以获得最终结果。
知道更多:数据结构+算法=程序
“数据+算法=程序”这个等式是由著名的“数据结构+算法=程序”变形而的。它由Pascal之父、结构化程序设计的先驱Niklaus Wirth先生最先提出,它抽象地概括了一个程序的最核心内容是其中的用于表达数据的数据结构和对数据进行处理的算法。而我们在这里提出的“数据+算法=程序”,则是具体地描述了一个程序由它要处理的数据以及对数据进行具体处理的算法共同组成。两个等式都是正确的,只是描述程序的角度不同而已。
数据和算法伴随我的一生。在小小的HelloWorld.exe中,也同样有数据和算法的存在。例如,向屏幕输出“Hello World!”的语句:
cout&&&Hello World!&&&
其中,“Hello World!”是一个要向屏幕输出的字符串数据。整个语句则代表了对这个字符串数据的处理:将字符串显示到屏幕上。数据和算法总是这样形影不离,成为我终身要完成的两大任务。
通过对资料整理,发现还有其他相关问题:
SOIL(Simple OpenGL Image Library) 顾名思义,简单的OpenGL图片库
其实载入图片的学习型过程中,我也学到了不少其他的东西,不过都是和图形有关的,比如gtk,opengl等。。。
有经验都来分享下吧,首先是在visual studio环境下配置GTK。
首先从这里下载GTK的完整版(
为了更好的掌握面向对象的编程思维,推荐几种常用的小技巧,来快速提升面向对象的编程。
1. 告别常量
2. 告别变量
3. 告别静态变量
4. 告别函数
5. 告别全局变量
6. 告别Map数组  
1.常量转变成常类型
  常量实例:
电脑技术网|电脑技术学习|手机使用|编程入门|手机软件|电脑硬件|C语言入门|PS教程|MAPGIS教程|SEO优化C++|C++教程|C++教程下载|C++基础教程|电脑技术网
如需学习更多相关知识,请访问的栏目,记得点赞哟!请记住我们的永久网址:
看过此文章的用户还看过:Linux下面如何进行C语言编程技术教程
查看: 2293|
摘要: 这篇文章介绍在LINUX下进行C语言编程所需要的基础知识,在这篇文章当中,我们将会学到以下内容:源程序编译、Makefile的编写、程序库的链接、程序的调试、头文件和系统求助。
1、源程序的编译
在Linux下面,如果要
这篇文章介绍在LINUX下进行C语言编程所需要的基础知识,在这篇文章当中,我们将会学到以下内容:源程序编译、Makefile的编写、程序库的链接、程序的调试、头文件和系统求助。
1、源程序的编译
在Linux下面,如果要编译一个C语言源程序,我们要使用GNU的gcc编译器。下面我们以一个实例来说明如何使用gcc编译器。
假设我们有下面一个非常简单的源程序(hello.c):
int main(int argc,char **argv)
printf("Hello Linux\n");
要编译这个程序,我们只要在命令行下执行:
gcc -o hello hello.c
gcc 编译器就会为我们生成一个hello的可执行文件,执行./hello就可以看到程序的输出结果了。命令行中 gcc表示我们是用gcc来编译我们的源程序,-o 选项表示我们要求编译器给我们输出的可执行文件名为hello 而hello.c是我们的源程序文件。
gcc编译器有许多选项,一般来说我们只要知道其中的几个就够了, -o选项我们已经知道了,表示我们要求输出的可执行文件名。 -c选项表示我们只要求编译器输出目标代码,而不必要输出可执行文件。 -g选项表示我们要求编译器在编译的时候提供我们以后对程序进行调试的信息。
知道了这三个选项,我们就可以编译我们自己所写的简单的源程序了,如果你想要知道更多的选项,可以查看gcc的帮助文档,那里有着许多对其它选项的详细说明。
2、Makefile的编写
假设我们有下面这样的一个程序,源代码如下:
/*& main.c */
#include "mytool1.h"
#include "mytool2.h"
int main(int argc,char **argv)
mytool1_print("hello");
mytool2_print("hello");
/*& mytool1.h& */
#ifndef _MYTOOL_1_H
#define _MYTOOL_1_H
void mytool1_print(char *print_str);
/*& mytool1.c& */
#include "mytool1.h"
void mytool1_print(char *print_str)
printf("This is mytool1 print %s\n",print_str);
/* mytool2.h */
#ifndef _MYTOOL_2_H
#define _MYTOOL_2_H
void mytool2_print(char *print_str);
/*& mytool2.c& */
#include "mytool2.h"
void mytool2_print(char *print_str)
printf("This is mytool2 print %s\n",print_str);
当然由于这个程序是很短的我们可以这样来编译
gcc -c main.c
gcc -c mytool1.c
gcc -c mytool2.c
gcc -o main main.o mytool1.o mytool2.o
这样的话我们也可以产生main程序,而且也不时很麻烦,但是如果我们考虑一下如果有一天我们修改了其中的一个文件(比如说mytool1.c)那么我们难道还要重新输入上面的命令?写一个SHELL脚本,让她帮我去完成不就可以了。是的对于这个程序来说,是可以起到作用的,但是当我们把事情想的更复杂一点,如果我们的程序有几百个源程序的时候,难道也要编译器重新一个一个的去编译?
为此,聪明的程序员们想出了一个很好的工具来做这件事情,这就是make。我们只要执行以下make,就可以把上面的问题解决掉。在我们执行make之前,我们要先编写一个非常重要的文件,--Makefile。对于上面的那个程序来说,可能的一个Makefile的文件是:
#&& 这是上面那个程序的Makefile文件
main:main.o mytool1.o mytool2.o
gcc -o main main.o mytool1.o mytool2.o
main.o:main.c mytool1.h mytool2.h
gcc -c main.c
mytool1.o:mytool1.c mytool1.h
gcc -c mytool1.c
mytool2.o:mytool2.c mytool2.h
gcc -c mytool2.c
有了这个Makefile文件,不过我们什么时候修改了源程序当中的什么文件,我们只要执行make命令,我们的编译器都只会去编译和我们修改的文件有关的文件,其它的文件她连理都不想去理的。
下面我们学习Makefile是如何编写的,在Makefile中也#开始的行都是注释行.Makefile中最重要的是描述文件的依赖关系的说明.一般的格式是:
target: components
第一行表示的是依赖关系,第二行是规则。
比如说我们上面的那个Makefile文件的第二行
main:main.o mytool1.o mytool2.o
表示我们的目标(target)main的依赖对象(components)是main.o mytool1.o mytool2.o 当倚赖的对象在目标修改后修改的话,就要去执行规则一行所指定的命令,就象我们的上面那个Makefile第三行所说的一样要执行 gcc -o main main.o mytool1.o mytool2.o 注意规则一行中的TAB表示那里是一个TAB键
Makefile有三个非常有用的变量.分别是&代表的意义分别是:
$@--目标文件,$^--所有的依赖文件,$&--第一个依赖文件。
如果我们使用上面三个变量,那么我们可以简化我们的Makefile文件为:
# 这是简化后的Makefile
main:main.o mytool1.o mytool2.o
gcc -o $@ $^
main.o:main.c mytool1.h mytool2.h
mytool1.o:mytool1.c mytool1.h
mytool2.o:mytool2.c mytool2.h
经过简化后我们的Makefile是简单了一点,不过人们有时候还想简单一点,这里我们学习一个Makefile的缺省规则
这个规则表示所有的.o文件都是依赖与相应的.c文件的,例如mytool.o依赖于mytool.c这样Makefile还可以变为:
# 这是再一次简化后的Makefile
main:main.o mytool1.o mytool2.o
gcc -o $@ $^
我们的Makefile 也差不多了,如果想知道更多的关于Makefile规则可以查看相应的文档。
3、程序库的链接
试着编译下面这个程序
/* temp.c */
int main(int argc,char **argv)
printf("Value:%f\n",value);
这个程序相当简单,但是当我们用 gcc -o temp temp.c 编译时会出现下面所示的错误。
/tmp/cc33Kydu.o: In function `main':
/tmp/cc33Kydu.o(.text+0xe): undefined reference to `log'
collect2: ld returned 1 exit status
出现这个错误是因为编译器找不到log的具体实现,虽然我们包括了正确的头文件,但是我们在编译的时候还是要连接确定的库。在Linux下,为了使用数学函数,我们必须和数学库连接,为此我们要加入 -lm 选项。gcc -o temp temp.c -lm这样才能够正确的编译,也许有人要问,前面我们用printf函数的时候怎么没有连接库呢?是这样的,对于一些常用的函数的实现,gcc编译器会自动去连接一些常用库,这样我们就没有必要自己去指定了。有时候我们在编译程序的时候还要指定库的路径,这个时候我们要用到编译器的 -L选项指定路径。比如说我们有一个库在 /home/hoyt/mylib下,这样我们编译的时候还要加上 -L/home/hoyt/mylib,对于一些标准库来说,我们没有必要指出路径。只要它们在起缺省库的路径下就可以了,系统的缺省库的路径/lib /usr/lib /usr/local/lib 在这三个路径下面的库,我们可以不指定路径。
还有一个问题,有时候我们使用了某个函数,但是我们不知道库的名字,这个时候怎么办呢?对于这个问题我也不知道答案,我只有一个傻办法,首先我到标准库路径下面去找看看有没有和我用的函数相关的库,我就这样找到了线程(thread)函数的库文件(libpthread.a)。 当然如果找不到,只有一个笨方法,比如我要找sin这个函数所在的库,就只好用 nm -o /lib/*.so|grep sin&~/sin 命令,然后看~/sin文件,到那里面去找了,在sin文件当中,我会找到这样的一行libm-2.1.2.so:00009fa0 W sin 这样我就知道了sin在 libm-2.1.2.so库里面,我用 -lm选项就可以了(去掉前面的lib和后面的版本标志,就剩下m了所以是 -lm)。
4、程序的调试
我们编写的程序不太可能一次性就会成功的,在我们的程序当中,会出现许许多多我们想不到的错误,这个时候我们就要对我们的程序进行调试了。
最常用的调试软件是gdb.如果你想在图形界面下调试程序,那么你现在可以选择xxgdb,记得要在编译的时候加入 -g选项,关于gdb的使用可以看gdb的帮助文件。由于我没有用过这个软件,所以我也不能够说出如何使用。不过我不喜欢用gdb,跟踪一个程序是很烦的事情,我一般用在程序当中输出中间变量的值来调试程序的。当然你可以选择自己的办法,没有必要去学别人的,现在有了许多IDE环境,里面已经自己带了调试器。
5、头文件和系统求助
有时候我们只知道一个函数的大概形式,不记得确切的表达式,或者是不记得着函数在那个头文件进行了说明,这个时候我们可以求助系统。
比如说我们想知道fread这个函数的确切形式,我们只要执行 man fread系统就会输出着函数的详细解释的,和这个函数所在的头文件说明了。如果我们要write这个函数的说明,当我们执行man write时,输出的结果却不是我们所需要的。因为我们要的是write这个函数的说明,可是出来的却是write这个命令的说明。为了得到write的函数说明我们要用 man 2 write,2表示我们用的write这个函数是系统调用函数,还有一个我们常用的是3表示函数是C的库函数。所谓程序调试,是指当程序的工作情况(运行结果)与设计的要求不一致&&通常是程序的运行结果不对时,科学地(而不是凭偶然的运气)通过一定的方法、使用一定的手段来检查程序中存在的设计问题(某种逻辑错误而不是语法、链接错误,修正语法、链接错误不是调试程序要做的事)。
当程序编译出错或者链接出错时,系统都将在Output输出窗口中随时显示出有关的提示信息或出错警告信息等(如果是编译出错,只要双击Output窗口中的出错信息就可以自动跳到出错的程序行,以便仔细查找)。但若编译和链接都正确,而执行结果又总是不正确时,这时就需要使用调试工具来帮着&侦察&出程序中隐藏着的出错位置(某种逻辑错误)。
强调:初学者常犯的错误是认为&编译和链接&都正确,程序就应该没有问题,怎么会结果不对呢?&编译和链接&都正确,只能说明程序没有语法和拼写上的错误,但在算法(逻辑)上有没有错,还得看结果对不对。反过来讲,无论让你设计一个什么样的程序,你都只写以下几行,则&编译和链接&肯定都正确,但能实现设计的要求吗?
#include &stdio.h&
void main(){
printf(&Hello World!\n&);
事实上,程序设计的重点完全不是修正编译和链接过程中的错误&&相对而言,这种工作基本没有技术含量,程序设计的主要工作是设计正确的算法。
推荐文章 TOP10提问回答都赚钱
> 问题详情
下列叙述中不正确的是()。(A)FORTRAN子程序可以单独编译(B)对一个FORTRAN源程序进行编译和连接无
悬赏:0&&答案豆&&&&提问人:匿名网友&&&&提问收益:0.00答案豆&&&&&&
下列叙述中不正确的是()。(A)FORTRAN子程序可以单独编译(B)对一个FORTRAN源程序进行编译和连接无误后可生成可执行文件(C)即使编译和连接都正确无误,FORTRAN77程序运行时仍可能出错(D)FORTRAN连接的主要任务是把函数库中的函数翻译成机器指令
发布时间:&&截止时间:
查看最佳答案前请先输入下方的验证!
网友回答&(共0条)
回答悬赏问题预计能赚取&5.00元收益
回答悬赏问题预计能赚取&3.00元收益
回答悬赏问题预计能赚取&5.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&5.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&5.00元收益
回答悬赏问题预计能赚取&5.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&3.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&5.00元收益
回答悬赏问题预计能赚取&3.00元收益
回答悬赏问题预计能赚取&12.00元收益
回答悬赏问题预计能赚取&12.00元收益
回答悬赏问题预计能赚取&3.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&5.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&3.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&5.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&3.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&3.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&5.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&5.00元收益
回答悬赏问题预计能赚取&20.00元收益
回答悬赏问题预计能赚取&20.00元收益
回答悬赏问题预计能赚取&5.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&1.00元收益
回答悬赏问题预计能赚取&3.00元收益
为你请到的专家
&&&&采纳率:76%&&&
&&采纳率:97%&&&
&&采纳率:88%&&&
&&&&采纳率:25%&&&
&&采纳率:90%&&&
[] [] [] [] [] [] [] [] [] [] [] []

我要回帖

更多关于 编译与链接的区别 的文章

 

随机推荐