1. C语言文件的编译与执行的四个阶段并分别描述
开发C程序有四个步骤:编辑、编译、连接和运行。
任何一个体系结构处理器上都可以使用C语言程序,只要该体系结构处理器有相应的C语言编译器和库,那么C源代码就可以编译并连接到目标二进制文件上运行。
1、预处理:导入源程序并保存(C文件)。
2、编译:将源程序转换为目标文件(Obj文件)。
3、链接:将目标文件生成为可执行文件(EXE文件)。
4、运行:执行,获取运行结果的EXE文件。
(1)类型转换在编译的哪个阶段扩展阅读:
将C语言代码分为程序的几个阶段:
1、首先,源代码文件测试。以及相关的头文件,比如stdio。H、由预处理器CPP预处理为.I文件。预编译的。文件不包含任何宏定义,因为所有宏都已展开,并且包含的文件已插入。我归档。
2、编译过程是对预处理文件进行词法分析、语法分析、语义分析和优化,生成相应的汇编代码文件。这个过程往往是整个程序的核心部分,也是最复杂的部分之一。
3、汇编程序不直接输出可执行文件,而是输出目标文件。汇编程序可以调用LD来生成可以运行的可执行程序。也就是说,您需要链接大量的文件才能获得“a.out”,即最终的可执行文件。
4、在链接过程中,需要重新调整其他目标文件中定义的函数调用指令,而其他目标文件中定义的变量也存在同样的问题。
2. C++类型转换规则、何时发生隐式类型转换及强制类型转换适用场合
C++做为强类型语言,要求编译期的类型声明与检查,要求表达式中各操作数的类型(包括赋值操作的左值和右值,以及形参和实参)具有一致性,但同时也允许一定的灵活性,允许类型在一定程度上的兼容,也就是允许类型遵循一定规则下的隐式转换和强制转换。
The type of the operand(s) determine whether an expression is legal and, if the expression is legal, determines the meaning of the expression. However, in C++ some types are related to one another. When two types are related, we can use an object or value of one type where an operand of the related type is expected. Two types are related if there is a conversion between them.
表达式是否合法取决于操作数的类型,而且合法的表达式其含义也由其操作数类型决定。但是,在 C++ 中,某些类型之间存在相关的依赖关系。若两种类型相关,则可在需要某种类型的操作数位置上,使用该类型的相关类型对象或值。如果两个类型之间可以相互 转换 ,则称这两个类型相关。
1.1 The Arithmetic Conversions 算术转换
The language defines a set of conversions among the built-in types. Among these, the most common are the arithmetic conversions , which ensure that the two operands of a binary operator, such as an arithmetic or logical operator, are converted to a common type before the operator is evaluated. That common type is also the result type of the expression.
C++ 语言为内置类型提供了一组转换规则,其中最常用的是 算术转换 。算术转换保证在执行操作之前,将二元操作符(如算术或逻辑操作符)的两个操作数转换为同一类型,并使表达式的值也具有相同的类型。
The rules define a hierarchy of type conversions in which operands are converted to the widest type in the expression. The conversion rules are defined so as to preserve the precision of the values involved in a multi-type expression. For example, if one operand is of type long double, then the other is converted to type long double regardless of what the second type is.
算术转换规则定义了一个类型转换层次,该层次规定了操作数应按什么次序转换为表达式中最宽的类型。在包含多种类型的表达式中,转换规则要确保计算值的精度。例如,如果一个操作数的类型是 long double,则无论另一个操作数是什么类型,都将被转换为 long double。
The simplest kinds of conversion are integral promotions . Each of the integral types that are smaller than int char, signed char, unsigned char, short, and unsigned shortis promoted to int if all possible values of that type fit in an int. Otherwise, the value is promoted to unsigned int. When bool values are promoted to int, a false value promotes to zero and true to one.
最简单的转换为 整型提升 :对于所有比 int 小的整型,包括 char、signed char、unsigned char、short 和 unsigned short,如果该类型的所有可能的值都能包容在 int 内,它们就会被提升为 int 型,否则,它们将被提升为 unsigned int。如果将 bool 值提升为 int ,则 false 转换为 0,而 true 则转换为 1。
需要注意的,上述所谓的转换只是运算时的类型转换,存储时还会转换为其声明时的类型。
1.2 Conversions between Signed and Unsigned Types 有符号与无符号类型之间的转换
When an unsigned value is involved in an expression, the conversion rules are defined to preserve the value of the operands. Conversions involving unsigned operands depend on the relative sizes of the integral types on the machine. Hence, such conversions are inherently machine dependent.
若表达式中使用了无符号( unsigned )数值,所定义的转换规则需保护操作数的精度。unsigned 操作数的转换依赖于机器中整型的相对大小,因此,这类转换本质上依赖于机器。
In expressions involving shorts and ints, values of type short are converted to int. Expressions involving unsigned short are converted to int if the int type is large enough to represent all the values of an unsigned short. Otherwise, both operands are converted to unsigned int. For example, if shorts are a half word and ints a word, then any unsigned value will fit inside an int. On such a machine, unsigned shorts are converted to int.
包含 short 和 int 类型的表达式, short 类型的值转换为 int 。如果 int 型足够表示所有 unsigned short 型的值,则将 unsigned short 转换为 int,否则,将两个操作数均转换为 unsigned int 。例如,如果 short 用半字表示而 int 用一个字表示,则所有 unsigned 值都能包容在 int 内,在这种机器上, unsigned short 转换为 int。
The same conversion happens among operands of type long and unsigned int. The unsigned int operand is converted to long if type long on the machine is large enough to represent all the values of the unsigned int. Otherwise, both operands are converted to unsigned long.
long 和 unsigned int 的转换也是一样的。只要机器上的 long 型足够表示 unsigned int 型的所有值,就将 unsigned int 转换为 long 型,否则,将两个操作数均转换为 unsigned long 。
On a 32-bit machine, long and int are typically represented in a word. On such machines, expressions involving unsigned ints and longs are converted to unsigned long.
在 32 位的机器上,long 和 int 型通常用一个字长表示,因此当表达式包含 unsigned int 和 long 两种类型,其操作数都应转换为 unsigned long 型。
Conversions for expressions involving signed and unsigned int can be surprising. In these expressions the signed value is converted to unsigned. For example, if we compare a plain int and an unsigned int, the int is first converted to unsigned. If the int happens to hold a negative value, the result will be converted as described as belows, with all the attendant problems discussed there.
对于包含 signed 和 unsigned int 型的表达式,其转换可能出乎我们的意料。表达式中的 signed 型数值会被转换为 unsigned 型。例如,比较 int 型和 unsigned int 型的简单变量,系统首先将 int 型数值转换为 unsigned int 型,如果 int 型的值恰好为负数,其结果将以下述方法转换,并带来其所有副作用。
The compiler applies conversions for both built-in and class type objects as necessary. Implicit type conversions take place in the following situations:
编译器在必要时将类型转换规则应用到内置类型和类类型的对象上。在下列情况下,将发生隐式类型转换:
In expressions with operands of mixed types, the types are converted to a common type:
在混合类型的表达式中,其操作数被转换为相同的类型:
An expression used as a condition is converted to bool:
用作条件的表达式被转换为 bool 类型:
Conditions occur as the first operand of the conditional (?:) operator and as the operand(s) to the logical NOT (!), logical AND (&&), and logical OR (||) operators. Conditions also appear in the if, while, for, and do while statements.
条件操作符(?:)中的第一个操作数以及逻辑非(!)、逻辑与(&&)和逻辑或(||)的操作数都是条件表达式。出现在 if、while、for 和 do while 语句中的同样也是条件表达式。
An expression used to initialize or assign to a variable is converted to the type of the variable:
用一表达式初始化某个变量,或将一表达式赋值给某个变量,则该表达式被转换为该变量的类型:
In addition,implicit conversions also occur ring function calls.
另外,在函数调用中也可能发生隐式类型转换。
3.1 static_cast
Any type conversion that the compiler performs implicitly can be explicitly requested by using a static_cast:
编译器隐式执行的任何类型转换都可以由 static_cast 显式完成:
Such casts are useful when assigning a larger arithmetic type to a smaller type. The cast informs both the reader of the program and the compiler that we are aware of and are not concerned about the potential loss of precision. Compilers often generate a warning for assignments of a larger arithmetic type to a smaller type. When we provide the explicit cast, the warning message is turned off.
当需要将一个较大的算术类型赋值给较小的类型时,使用强制转换非常有用。此时,强制类型转换告诉程序的读者和编译器:我们知道并且不关心潜在的精度损失。对于从一个较大的算术类型到一个较小类型的赋值,编译器通常会产生警告。当我们显式地提供强制类型转换时,警告信息就会被关闭。
A static_cast is also useful to perform a conversion that the compiler will not generate automatically. For example, we can use a static_cast to retrieve a pointer value that was stored in a void* pointer:
如果编译器不提供自动转换,使用 static_cast 来执行类型转换也是很有用的。例如,下面的程序使用 static_cast 找回存放在 void* 指针中的值:
When we store a pointer in a void* and then use a static_cast to cast the pointer back to its original type, we are guaranteed that the pointer value is preserved. That is, the result of the cast will be equal to the original address value.
可通过 static_cast 将存放在 void* 中的指针值强制转换为原来的指针类型,此时我们应确保保持指针值。也就是说,强制转换的结果应与原来的地址值相等。
3.2 const_cast
A const_cast, as its name implies, casts away the constness of its expression. For example, we might have a function named string_ that we are certain reads, but does not write, its single parameter of type char*. If we have access to the code, the best alternative would be to correct it to take a const char*. If that is not possible, we could call string_ on a const value using a const_cast:
const_cast ,顾名思义,将 转换掉 表达式的 const 性质。例如,假设有函数 string_,只有唯一的参数,为 char* 类型,我们对该函数只读不写。在访问该函数时,最好的选择是修改它让它接受 const char* 类型的参数。如果不行,可通过 const_cast 用一个 const 值调用 string_ 函数:
Only a const_cast can be used to cast away constness. Using any of the other three forms of cast in this case would result in a compile-time error. Similarly, it is a compile-time error to use the const_cast notation to perform any type conversion other than adding or removing const.
只有使用 const_cast 才能将 const 性质转换掉。在这种情况下,试图使用其他三种形式的强制转换都会导致编译时的错误。类似地,除了添加或删除 const 特性,用 const_cast 符来执行其他任何类型转换,都会引起编译错误。
3.3 reinterpret_cast
A reinterpret_cast generally performs a low-level reinterpretation of the bit pattern of its operands.
reinterpret_cast 通常为操作数的位模式提供较低层次的重新解释。
A reinterpret_cast is inherently machine-dependent. Safely using reinterpret_cast requires completely understanding the types involved as well as the details of how the compiler implements the cast.
reinterpret_cast 本质上依赖于机器。为了安全地使用 reinterpret_cast,要求程序员完全理解所涉及的数据类型,以及编译器实现强制类型转换的细节。
在引入命名的强制类型转换操作符之前,显式强制转换用圆括号将类型括起来实现:
The effect of this cast is the same as using the reinterpret_cast notation. However, the visibility of this cast is considerably less, making it even more difficult to track down the rogue cast.
效果与使用 reinterpret_cast 符号相同,但这种强制转换的可视性比较差,难以跟踪错误的转换。
Depending on the types involved, an old-style cast has the same behavior as a const_cast, a static_cast, ora reinterpret_cast. When used where a static_cast or a const_cast would be legal, an old-style cast does the same conversion as the respective named cast. If neither is legal, then an old-style cast performs a reinterpret_cast. For example, we might rewrite the casts from the previous section less clearly using old-style notation:
旧式强制转换依赖于所涉及的数据类型,具有与 const_cast、 static_cast 和 reinterpret_cast 一样的行为。在合法使用 static_cast 或 const_cast 的地方,旧式强制转换提供了与各自对应的命名强制转换一样的功能。如果这两种强制转换均不合法,则旧式强制转换执行 reinterpret_cast 功能。例如,我们可用旧式符号重写上一节的强制转换:
By using a cast, the programmer turns off or dampens normal type-checking. We strongly recommend that programmers avoid casts and believe that most well-formed C++ programs can be written without relying on casts.
强制类型转换关闭或挂起了正常的类型检查。强烈建议程序员避免使用强制类型转换,不依赖强制类型转换也能写出很好的 C++ 程序。
arithmetic conversion(算术转换)
A conversion from one arithmetic type to another. In the context of the binary arithmetic operators, arithmetic conversions usually attempt to preserve precision by converting a smaller type to a larger type (e.g., small integral types, such as char and short, are converted to int).
算术类型之间的转换。在使用二元算术操作符的地方,算术转换通常将较小的类型转换为较大的类型,以确保精度(例如,将小的整型 char 型和 short 型转换为 int 型)。
dynamic_cast
Used in combination with inheritance and run-time type identification.
用于结合继承和运行时类型识别。
implicit conversion(隐式类型转换)
A conversion that is automatically generated by the compiler. Given an expression that needs a particular type but has an operand of a differing type , the compiler will automatically convert the operand to the desired type if an appropriate conversion exists.
编译器自动实现的类型转换。假设表达式需要某种特定类型的数值,但其操作数却是其他不同的类型, 此时如果系统定义了适当的类型转换 ,编译器会自动根据转换规则将该操作数转换为需要的类型。
integral promotions(整型提升)
Subset of the standard conversions that take a smaller integral type to its most closely related larger type. Integral types (e.g. short, char, etc.) are promoted to int or unsigned int.
整型提升是标准类型转换规则的子集,它将较小的整型转换为最接近的较大数据类型。整型(如 short、char 等)被提升为 int 型或 unsigned int 型。
reinterpret_cast
Interprets the contents of the operand as a different type. Inherently machine-dependent and dangerous.
将操作数内容解释为另一种不同的类型。这类强制转换本质上依赖于机器,而且是非常危险的。
static_cast
An explicit request for a type conversion that the compiler would do implicitly. Often used to override an implicit conversion that the compiler would otherwise perform.
编译器隐式执行的任何类型转换都可以由 static_cast 显式完成。我们常常使用 static_cast 取代由编译器实现的隐式转换。
-End-
3. 传统意义上的c/c++语言,类型推断是在哪个阶段完成的
不存在类型推断,根据声明,c/c++编译器可以直接获取该变量类型。如果是类型检查的话在词法分析阶段就可以捕获类型不匹配错误。当然如果非要放到语法分析阶段也可以。
4. C语言源程序的编译过程包括哪三个阶段
编译:将源程序转换为扩展名为.obj的二进制代码
连接:将obj文件进行连接,加入库函数等生成可执行文件
运行:执行可执行文件,有错返回修改,无错结束
5. 编译器的工作分为哪几个阶段
编译器就是一个普通程序,没什么大不了的
什么是编译器?
编译器是一个将高级语言翻译为低级语言的程序。
首先我们一定要意识到编译器就是一个普通程序,没什么大不了的。
在没有弄明白编译器如何工作之前你可以简单的把编译器当做一个黑盒子,其作用就是输入一个文本文件输出一个二进制文件。
基本上编译器经过了以下几个阶段,等等,这句话教科书上也有,但是我相信很多同学其实并没有真正理解这几个步骤到底在说些什么,为了让你彻底理解这几个步骤,我们用一个简单的例子来讲解。
假定我们有一段程序:
while (y < z) {
int x = a + b;
y += x;
}
那么编译器是怎样把这一段程序人类认识的程序转换为CPU认识的二进制机器指令呢?
提取出每一个单词:词法分析
首先编译器要把源代码中的每个“单词”提取出来,在编译技术中“单词”被称为token。其实不只是每个单词被称为一个token,除去单词之外的比如左括号、右括号、赋值操作符等都被称为token。
从源代码中提取出token的过程就被称为词法分析,Lexical Analysis。
经过一遍词法分析,编译器得到了以下token:
T_While while
T_LeftParen (
T_Identifier y
T_Less <
T_Identifier z
T_RightParen )
T_OpenBrace {
T_Int int
T_Identifier x
T_Assign =
T_Identifier a
T_Plus +
T_Identifier b
T_Semicolon ;
T_Identifier y
T_PlusAssign +=
T_Identifier x
T_Semicolon ;
T_CloseBrace }
就这样一个磁盘中保存的字符串源代码文件就转换为了一个个的token。
这些token想表达什么意思:语法分析
有了这些token之后编译器就可以根据语言定义的语法恢复其原本的结构,怎么恢复呢?
原来,编译器在扫描出各个token后根据规则将其用树的形式表示出来,这颗树就被称为语法树。
语法树是不是合理的:语义分析
有了语法树后我们还要检查这棵树是不是合法的,比如我们不能把一个整数和一个字符串相加、比较符左右两边的数据类型要相同,等等。
这一步通过后就证明了程序合法,不会有编译错误。
6. C语言强制类型转换
强制类型转换是把变量从一种类型转换为另一种数据类型。
例如,如果您想存储一个 long 类型的值到一个简单的整型中,您需要把 long 类型强制转换为 int 类型。您可以使用强制类型转换运算符来把值显式地从一种类型转换为另一种类型。
(6)类型转换在编译的哪个阶段扩展阅读:
举例说明
使用强制类型转换运算符把一个整数变量除以另一个整数变量,得到一个浮点数:
#include <stdio.h>int main()
{
int sum = 17, count = 5;
double mean;
mean = (double) sum / count;
printf("Value of mean : %f
", mean );
}
当上面的代码被编译和执行时,它会产生下列结果:
Value of mean : 3.400000
7. C语言的编译阶段指的什么阶段
把你写的程序代码翻译为机器可以读懂的语言,也就是机器语言。
也就是把程序代码翻译为001010101的二进制程序代码
8. 何谓隐式类型转换其转换规则如何
数值的类型转换分为强制性转换(我们人为的转换)和自动转换(也就是隐式转换,编译器自己进行的转换,不经我们的同意)
要想知道什么是隐式转换,那你首先得清楚数值共可以分为几个类型,其中包括char=short<int<unsingned<long=float<double.他们的精确度是随之增加的,他们能表示数值的范围也是越来越大的。如果同类型的数值相操作(加减乘除等),是不会发生类型转换,如果是不同类型数值相操作,比如说short型数值和int型数值相操作,那么小取值范围的类型(short)会先隐式转换为取值范围大的类型(int),然后再进行数值间的操作,得出来的结果也是int型。
我说道这里不知道你能否看懂。建议你看看谭浩强的《c程序设计》,里面讲的比较详细。
9. java代码的编译期绑定和运行期绑定是什么意思
如果打包成jar的话很好如果是exe的话就有点麻烦了可参考:想要把java生成可执行文件需要第三方软件的支持,不过在没有安装JDK的机器上是不可能运行JAVA程序的,哪怕是编译成为exe文件。将Java应用程序本地编译为EXE的几种方法(推荐使用JOVE和JET)1.从获得一个TowerJ编译器,该编译器可以将你的CLASS文件编译成EXE文件。2.利用微软的SDK-Java4.0所提供的jexegen.exe创建EXE文件,这个软件可以从微软的网站免费下载,地址如下:7.Instantiations公司的JOVE/jove/ejovesystem.htmJOVE公司合并了以前的SuperCede,一个优秀的本地编译器,现在SuperCede已经不复存在了。8.JToEXEBravoZuluConsulting,Inc开发的一款本地编译器,本来可以从该公司的网页上免费下载的,不过目前在该公司的主页上找不到了。