① c语言编译后的是什么东西
C/C++编译连接后,生成的exe文件都是二进制的机器码
快和慢的简单概念就是做同样的一件事情,一个用时少,一个用时多
也就是一个用的指令周期少,一个用的指令周期多
② c语言中预处理命令都有哪些
我们可以在C源程序中插入传给编译程序的各中指令,这些指令被称为预处理器指令,它们扩充了程序设计的环境。现把常用的预处理命令总结如下:
1. 预处理程序
按照ANSI标准的定义,预处理程序应该处理以下指令:
#if #ifdef #ifndef #else #elif
#endif
#define
#undef
#line
#error
#pragma
#include
显然,上述所有的12个预处理指令都以符号#开始,,每条预处理指令必须独占一行。
2. #define
#define指令定义一个标识符和一个串(也就是字符集),在源程序中发现该标识符时,都用该串替换之。这种标识符称为宏名字,相应的替换称为宏代换。一般形式如下:
#define macro-name char-sequence
这种语句不用分号结尾。宏名字和串之间可以有多个空白符,但串开始后只能以新行终止。
例如:我们使用LEFT代表1,用RIGHT代表0,我们使用两个#define指令:
#define LEFT 1
#define RIGHT 0
每当在源程序中遇到LEFT或RIGHT时,编译程序都用1或0替换。
定义一个宏名字之后,可以在其他宏定义中使用,例如:
#define ONE 1
#define TWO ONE+ONE
#define THREE ONE+TWO
宏代换就是用相关的串替代标识符。因此,如果希望定义一条标准错误信息时,可以如下定义:
#define ERROR_MS “Standard error on input \n”
如果一个串长于一行,可在行尾用反斜线”\”续行,如下:
#define LONG_STRING “This is a very very long \
String that is used as an example”
3. #error
#error指令强制编译程序停止编译,它主要用于程序调试。#error指令的一般形式是:
#error error-message
注意,宏串error-message不用双引号包围。遇到#error指令时,错误信息被显示,可能同时还显示编译程序作者预先定义的其他内容。
4. #include
程序中的#include指令要求编译程序读入另一个源文件。被读入文件的名字必须用双引号(“”)或一对尖括号(<>)包围,例如:
#include “stdio.h”
#include <stdio.h>
都使C编译程序读入并编译头文件以用于I/O系统库函数。
包含文件中可以包含其他#include指令,称为嵌套包含。允许的最大嵌套深度随编译器而变。
文件名被双括号或尖括号包围决定了对指定文件的搜索方式。文件名被尖括号包围时,搜索按编译程序作者的定义进行,一般用于搜索某些专门放置包含文件的特殊目录。当文件名被双括号包围时,搜索按编译程序实时的规定进行,一般搜索当前目录。如未发现,再按尖括号包围时的办法重新搜索一次。
通常,绝大多数程序员使用尖括号包围标准的头文件,双引号用于包围与当前程序相关的文件名。
5. 条件编译指令
若干编译指令允许程序员有选择的编译程序源代码的不同部分,这种过程称为条件编译。
5.1#if、#else、#elif #endif
条件编译指令中最常用的或许是#if,#else,#elif和#endif。这些指令允许程序员根据常数表达式的结果有条件的包围部分代码。
#if的一般形式是:
#if constant-expression
Statement sequence
#endif
如#if后的常数表达式为真,则#if和#endif中间的代码被编译,否则忽略该代码段。#endif标记#if块的结束。
#else指令的作用与C语言的else相似,#if指令失败时它可以作为备选指令。例如:
#include <stdio.h>
#define MAX 100
Int main(void)
{
#if MAX>99
printf(“Compiled for array greater than 99.\n”);
#else
printf(“Complied for small array.\n”);
#endif
return 0;
}
注意,#else既是标记#if块的结束,也标记#else块的开始。因为每个#if只能写一个#endif匹配。
#elif指令的意思是“否则,如果”,为多重编译选择建立一条if-else-if(如果-否则-如果链)。如果#if表达式为真,该代码块被编译,不测试其他#elif表达式。否则,序列中的下一块被测试,如果成功则编译之。一般形式如下:
#if expression
Statement sequence
#elif expression1
Statement sequence
#elif expression2
Statement sequence
.
.
.
#elif expression
Statement sequence
#endif
5.2#ifdef和#ifndef
条件编译的另一个方法是使用编译指令#ifdef和#ifndef,分别表示“如果已定义”和“如果未定义”。#ifdef的一般形式如下:
#ifdef macro-name
Statement sequence
#endif
如果macro-name原先已经被一个#define语句定义,则编译其中的代码块。
#ifndef的一般形式是:
#ifndef macro-name
Statement sequence
#endif
如果macro-name当前未被#define语句定义,则编译其中的代码块。
我认为,用这种,可以很方便的开启/关闭整个程序的某项特定功能。
#ifdef和#ifndef都可以使用#else或#elif语句。
#inlucde <stdio.h>
#define T 10
Int main(void)
{
#ifdef t
Printf(“Hi T\n”);
#else
Printf(“Hi anyone\n”);
#endif
#ifndef M
Printf(“M Not Defined\n”);
#endif
Return 0;
}
6. #undef
#undef指令删除前面定义的宏名字。也就是说,它“不定义”宏。一般形式为:
#undef macro-name
7. 使用defined
除#ifdef之外,还有另外一种确定是否定义宏名字的方法,即可以将#if指令与defined编译时操作符一起使用。defined操作符的一般形式如下:
defined macro-name
如果macro-name是当前定义的,则表达式为真,否则为假。
例如,确定宏MY是否定义,可以使用下列两种预处理命令之一:
#if defined MY
或
#ifdef MY
也可以在defined之前加上感叹号”!”来反转相应的条件。例如,只有在DEBUG未定义的情况下才编译。
#if !defined DEBUG
Printf(“Final Version!\n”);
#endif
使用defined的一个原因是,它允许由#elif语句确定的宏名字存在。
8. #line
#line指令改变__LINE__和__FILE__的内容。__LINE__和__FILE__都是编译程序中预定义的标识符。标识符__LINE__的内容是当前被编译代码行的行号,__FILE__的内容是当前被编译源文件的文件名。#line的一般形式是:
#line number “filename”
其中,number是正整数并变成__LINE__的新值;可选的“filename”是合法文件标识符并变成__FILE__的新值。#line主要用于调试和特殊应用。
9. #pragma
#pragma是编译程序实现时定义的指令,它允许由此向编译程序传入各种指令。例如,一个编译程序可能具有支持跟踪程序执行的选项,此时可以用#pragma语句选择该功能。编译程序忽略其不支持的#pragma选项。#pragma提高C源程序对编译程序的可移植性。
10. 预处理操作符#和##
有两个预处理操作符:#和##,它们可以在#define中使用。
操作符#通常称为字符串化的操作符,它把其后的串变成用双引号包围的串。例如:
#include <stdio.h>
#define mkstr(s) #s
int main(void)
{
Printf(mkstr(I like C));
Return 0;
}
预处理程序把以下的语句:
Printf(mkstr(I like C));
变成
Printf(“I like C”);
操作符##把两个标记拼在一起,形成一个新标记。例如:
#include <stdio.h>
#define concat(a,a) a##b
int main(void)
{
Int xy = 10;
Printf(“%d”,concat(x,y));
Return 0;
}
预处理程序把以下语句:
Printf(“%d”,concat(x,y));
变成
Printf(“%d”,xy);
操作符#和##主要作用是允许预处理程序对付某些特殊情况,多数程序中并不需要。
11. 预定义宏
C规范了5个固有的预定义宏,它们是:
__LINE__
__FILE__
__DATE__
__TIME__
__STDC__
__LINE__和__FILE__包含正在编译的程序的行号和文件名。
__DATE__和内容形如month/day/year(月/日/年)的串,代表源文件翻译成目标码的日期。
__TIME__中的串代表源代码编译成目标码的时间,形如hour:minute:second(时:分:秒)
如果__STDC__的内容是十进制常数1,则表示编译程序的实现符合标准C。
③ c语言一次完成编译、连接和执行用什么键
C/C++语言的完整编译过程是 一、预编译 处理#define #if #include这类#开头的语句,这些称为预编译指令。这个过程中会把.h文件和.c/.cpp文件组合成最终交给compile过程的原文件。这个原文件是不包含任何#开头的语句的。所有#define定义的宏也会被替换。 二、编译把上面那个原文件编译成.o或者VC里是.obj文件。这个文件保存了机器码化的函数、函数的描述、全局变量的描述、乃至段的描述等等。 三、连接把可执行程序需要的所有的编译过程产生的.o或者.obj文件组合到一起。(这里也包括.lib文件,.lib文件件本质上就是打包的.obj文件集合)。另外连接过程还会组合一些其他数据,比如资源、可执行文件头等等。
④ C语言中在main函数之前会执行什么
C语言执行本程序主函数始,本程序主函数结束 其余函数都调用程,至于文件类预编译命令既叫预编译编译前完预编译指令指示程序式编译前由编译器进行操作放程序任何位置。
⑤ c语言中在main函数之前会执行什么
都胡扯,一个C语言的执行是从本程序的主函数开始,到本程序的主函数结束。 其余函数都是一个被调用的过程。
至于头文件之类的预编译命令,既然叫预编译那就是编译之前完成的。预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。
⑥ C语言的源程序必须通过什么和什么才能被计算机执行
编译和链接。
每一个C语言程序必须要经过编译和链接才能被计算机执行,编译是将C源码翻译成机器码,链接是将将二进制目标文件装配成一个具有特定格式的二进制可执行文件,比如Windows平台上是PE格式,一般以.exe为扩展名。
一个C语言程序从源码到计算机系统可以执行,更细致的划分为:预处理——编译——汇编——链接。预处理是对C语言源码进行文本处理,编译阶断是将C源码经C编译器生成汇编代码,汇编阶断是将汇编代码经汇编器生成二进制机器码文件。这两个合拢起来,笼统的可以叫做编译阶断。
⑦ 初学c语言时,输入程序后运行,是执行还是预编译预编译是什么为什么最开始要有#include如
预编译是把一个工程中较稳定的代码预先编译好放在一个文件里.这些预先编译好的代码可以是任何的C/C++代码。而输入程序后的运行,只是将代码编译成了obj(object)文件,所有obj文件经链接(link)成为可执行文件。而你说的执行,应该就是点击最后生成的.exe文件了。开始要有的#include,是表明要包含的头文件,或者其它的保存的代码文件。只有这样,你才可以引用到那个文件中的代码,来供目前的文件来使用。
至于你说的什么大型游戏的编程,应该也是这样的一套,因为C语言就是上述生成文件的套路。游戏的编程,初学的话可以建议看《游戏编程入门》( 美 哈本),这本书基于windows平台,是为几乎没有游戏开发经验的初学者写的,循序渐进,从2D讲到3D 的一些基本技术,其中的例子也非常经典,看完书基本就可以做出不错的2D 游戏了,也有了一定的3D基础了,之后再看一些深入的书籍像《Windows游戏编程大师技巧》。
⑧ C语言文件的编译与执行的四个阶段并分别描述是什么
采纳了加我不懂问我</b> 一 C编译过程概述 目前linux下最常用的C语言编译器是GCC(GNU Compiler Collection),它是GNU项目中符合ANSI C标准的编译系统,能够编译用C、C++和Object C等语言编写的程序.GCC不仅功能非常强大,结构也异常灵活.最值得称道的一点就是它可以通过不同的前端模块来支持各种语言,如Java、Fortran、Pascal、Mola-3和Ada等. Linux系统下的gcc(GNU C Compiler)是GNU推出的功能强大、性能优越的多平台编译器,是GNU的代表作品之一。gcc是可以在多种硬体平台上编译出可执行程序的超级编译器,其执行效率与一般的编译器相比平均效率要高20%~30%。 使用GCC编译程序时,编译过程可以被细分为四个阶段:
◆ 预处理(Pre-Processing)
◆ 编译(Compiling)
◆ 汇编(Assembling)
◆ 链接(Linking) 二 编译过程中各种文件介绍 1.以扩展名区分文件类型.c为后缀的文件,C语言源代码文件;
.a为后缀的文件,是由目标文件构成的档案库文件;
.C,.cc或.cxx 为后缀的文件,是C++源代码文件;
.h为后缀的文件,是程序所包含的头文件;
.i 为后缀的文件,是已经预处理过的C源代码文件;
.ii为后缀的文件,是已经预处理过的C++源代码文件;
.m为后缀的文件,是Objective-C源代码文件;
.o为后缀的文件,是编译后的目标文件;
.s为后缀的文件,是汇编语言源代码文件;
.S为后缀的文件,是经过预编译的汇编语言源代码文件。 2.LINUX目标文件描述 LINUX 平台下三种主要的可执行文件格式:a.out(assembler and link editor output 汇编器和链接编辑器的输出)、COFF(Common Object File Format 通用对象文件格式)、ELF(Executable and Linking Format 可执行和链接格式)。其中ELF是x86 Linux系统 下的一种常用目标文件(object file)格式,有三种主要类型: (1)适于连接的可重定位文件(relocatable file),可与其它目标文件一起创建可执行文件和共享目标文件。编译产生的.o文件就属于这类。
(2)适于执行的可执行文件(executable file),用于提供程序的进程映像,加载到内存执行。这就是编译、链接之后形成的最终文件。
(3)共享目标文件(shared object file),连接器可将它与其它可重定位文件和共享目标文件连接成其它的目标文件,动态连接器又可将它与可执行文件和其它共享目标文件结合起来创建一个进程映像。这就是库文件,只指动态库文件。 详细了解请看本人收藏的《LINUX可执行文件分析》 三 编译过程详解 C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接。编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程。链接是把目标文件、操作系统的启动代码和用到的库文件进行组织形成最终生成可执行代码的过程。过程图解如下:
从图上可以看到,整个代码的编译过程分为编译和链接两个过程,编译对应图中的大括号括起的部分,其余则为链接过程。 1. 编译过程 编译过程又可以分成两个阶段:编译和汇编。 1)编译 编译是读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,源文件的编译过程包含两个主要阶段: 第一个阶段是预处理阶段,在正式的编译阶段之前进行。预处理阶段将根据已放置在文件中的预处理指令来修改源文件的内容。如#include指令就是一个预处理指令,它把头文件的内容添加到.cpp文件中。这个在编译之前修改源文件的方式提供了很大的灵活性,以适应不同的计算机和操作系统环境的限制。一个环境需要的代码跟另一个环境所需的代码可能有所不同,因为可用的硬件或操作系统是不同的。在许多情况下,可以把用于不同环境的代码放在同一个文件中,再在预处理阶段修改代码,使之适应当前的环境。主要是以下几方面的处理: (1)宏定义指令, 如 #define a b
对于这种伪指令,预编译所要做的是将程序中的所有a用b替换,但作为字符串常量的 a则不被替换。还有 #undef,则将取消对某个宏的定义,使以后该串的出现不再被替换。 (2)条件编译指令, 如#ifdef,#ifndef,#else,#elif,#endif等。
这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉。
(3)头文件包含指令, 如#include "FileName"或者#include <FileName>等。 在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),同时包含有各种外部符号的声明。采用头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用。因为在需要用到这些定义的C源程序中,只需加上一条#include语句即可,而不必再在此文件中将这些定义重复一遍。预编译程序将把头文件中的定义统统都加入到它所产生的输出文件中,以供编译程序对之进行处理。包含到c源程序中的头文件可以是系统提供的,这些头文件一般被放在 /usr/include目录下。在程序中#include它们要使用尖括号(< >)。另外开发人员也可以定义自己的头文件,这些文件一般与c源程序放在同一目录下,此时在#include中要用双引号("")。
(4)特殊符号,预编译程序可以识别一些特殊的符号。
例如在源程序中出现的LINE标识将被解释为当前行号(十进制数),FILE则被解释为当前被编译的C源程序的名称。预编译程序对于在源程序中出现的这些串将用合适的值进行替换。
预编译程序所完成的基本上是对源程序的“替代”工作。经过此种替代,生成一个没有宏定义、没有条件编译指令、没有特殊符号的输出文件。这个文件的含义同没有经过预处理的源文件是相同的,但内容有所不同。下一步,此输出文件将作为编译程序的输出而被翻译成为机器指令。
第二个阶段编译、优化阶段,经过预编译得到的输出文件中,只有常量;如数字、字符串、变量的定义,以及C语言的关键字,如main,if,else,for,while,{,}, +,-,*,\等等。
编译程序所要作得工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码。
优化处理是编译系统中一项比较艰深的技术。它涉及到的问题不仅同编译技术本身有关,而且同机器的硬件环境也有很大的关系。优化一部分是对中间代码的优化。这种优化不依赖于具体的计算机。另一种优化则主要针对目标代码的生成而进行的。
对于前一种优化,主要的工作是删除公共表达式、循环优化(代码外提、强度削弱、变换循环控制条件、已知量的合并等)、复写传播,以及无用赋值的删除,等等。 后一种类型的优化同机器的硬件结构密切相关,最主要的是考虑是如何充分利用机器的各个硬件寄存器存放的有关变量的值,以减少对于内存的访问次数。另外,如何根据机器硬件执行指令的特点(如流水线、RISC、CISC、VLIW等)而对指令进行一些调整使目标代码比较短,执行的效率比较高,也是一个重要的研究课题。
2)汇编
汇编实际上指把汇编语言代码翻译成目标机器指令的过程。对于被翻译系统处理的每一个C语言源程序,都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。目标文件由段组成。通常一个目标文件中至少有两个段:代码段:该段中所包含的主要是程序的指令。该段一般是可读和可执行的,但一般却不可写。数据段:主要存放程序中要用到的各种全局变量或静态的数据。一般数据段都是可读,可写,可执行的。 2. 链接过程 由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。
例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。
链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够诶操作系统装入执行的统一整体。
根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种: (1)静态链接 在这种链接方式下,函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。 (2)动态链接
在此种方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。
对于可执行文件中的函数调用,可分别采用动态链接或静态链接的方法。使用动态链接能够使最终的可执行文件比较短小,并且当共享对象被多个进程使用时能节约一些内存,因为在内存中只需要保存一份此共享对象的代码。但并不是使用动态链接就一定比使用静态链接要优越。在某些情况下动态链接可能带来一些性能上损害。四 编译过程实例描述 linux中使用的gcc编译器把上述的几个过程集成,一个命令就能完成编译的整个过程。为了详细说明每个步骤,下面我们将分部执行。下图是gcc代理的编译过程
例程: 在linux下创建文件hello.c,内容如下,
#include <stdio.h>
int main(void)
{
printf ("Hello,everybody!\n");
return 0;
} ◆ 预处理(Pre-Processing)
使用-E参数可以让GCC在预处理结束后停止编译过程,对应的命令是cpp,
# gcc -E hello.c -o hello.i 用编辑器打开hello.i,可以看到stdio.h文件被展开到了hello.i中。 ◆ 编译(Compiling)
使用-S参数将hello.i编译为汇编程序,使用的命令是cc -S,
#gcc –S hello.i –o hello.s 用编辑器打开hello.s,显然已经变成了汇编代码。 ◆ 汇编(Assembling)
使用-c参数将hello.s编译为目标文件,对应的命令是as,
#gcc –c hello.s –o hello.o 可以利用工具readelf或者objmp读出hello.o的信息。 ◆ 链接(Linking) 产生可执行文件,利用命令ld
# gcc hello.o -o hello
利用readelf,可以看到hello.o和hello文件的区别。
⑨ C语言既可以编译执行又可以解释执行吗
目前我知道的C语言只能编译执行,就是先编译成二进制的exe文件才能执行。
脚本语言才可以解释执行。
⑩ C语言编译执行的全过程是怎样的
预处理阶断:这个就是那些#include啥的。
编译阶断:把C语言的代码转成汇编语言代码,比如 int a = 2; 它会生成mov a, 2;
汇编阶断:把汇编代码转换成机器码,比如把mov a , 2 ; 转成 cd07 (mov指令的机器码中的一种机器码)
链接阶断:制作成一个可执行文件,比如windows是PE的可执行文件,linux是elf的可执行文件,要制作成可以运行的程序。