1.为什么C语言程序中的常量也需要确定数据类型?如何确定字面量常量的数据类型?
答:因为C语言程序中的常量可能出现在一个表达式中,或者作为一个初始值被赋值给某个变量,编译器需要根据表达式中变量和常量的类型确定表达式按什么数据类型进行运算,编译器也需要根据编程语言标准规范确定如何将常数字面量转换为相应的机器数,例如,带小数点的字面量就按浮点数格式转换为二进制表示的浮点数,一个十进制数串就直接转换为二进制数串,并根据规定确定其数据类型。
编译器根据字面量的形式和转换后数值的范围确定其类型,例如,20.0和2.85E10都属于浮点类型,0x12BF是十六进制表示的整数类型,2和2147483648是十进制表示的整数类型,"good!"则是ASCII码表示的字符串。对于整型常数字面量,在数字串最后加u或U时,表示无符号整型数,如字面量12345U和0x2B3Cu明显地表示为无符号整型数,若在数字串后不加u或U,则需要按C语言标准ISO C90和C99中相应的规定确定数据类型。例如,字面量2147483648(数值为2 31 )在32位机器ISO C90标准下是unsigned int型,而在64位机器中或者ISO C99标准下则是long long型。
2.一个C语言表达式中同时有整型变量、浮点型变量和整型常数,如2 * i * x(其中,i为int型,x为float型),则表达式按什么数据类型进行计算?
答:在C语言表达式中,如果混合使用不同类型的变量和常量,则应使用一个规则集合来完成数据类型的自动转换。以下是C语言程序数据类型转换的基本规则:在表达式中,(unsigned)char和(unsigned)short类型都应自动提升为int类型;在包含两种以上数据类型的任何表达式中,较低级别的数据类型应提升为较高级别的数据类型;数据类型级别从高到低的顺序依次是long double、double、float、unsigned long long、long long、unsigned long、long、unsigned int、int;当long和int具有相同位数时,unsigned int级别高于long。例如,在表达式2*i*x(其中,i为int型,x为float型)中,2和i应等值转换为float类型后再按float类型进行乘运算。
在赋值语句中,计算结果被转换为要被赋值的那个变量的类型,这个过程可能导致级别提升(被赋值的类型级别高)或者降级(被赋值的类型级别低),提升是按等值转换到表数范围更大的类型,通常是扩展操作或整数转浮点数类型,一般情况下不会有溢出问题,而降级可能因为表数范围缩小而导致数据溢出问题。
3.当函数头部说明的返回值类型与函数定义中return语句给出的表达式中的数据类型不一致时,编译器会如何处理?
答:函数的返回值通过返回语句return说明,return语句中的表达式给出了返回值的计算方法,C语言要求return语句中表达式的类型必须能够转换为函数头部说明的返回值类型,并且返回的值为转换类型后计算出来的值。例如,对于以下funct()函数:
因为函数头部说明的返回值类型为int,而return语句给出的表达式中有浮点数字面量,所以编译器将先按浮点数类型进行表达式计算,得到的浮点数等值转换为int型数值(小数部分丢弃)后,作为返回值返回。
4.在函数调用时,若调用函数传给被调用函数的实参类型与被调用函数定义中的形参类型不同,则编译器会如何处理?
答:编译器会将实参强制类型转换为形参类型表示的数值,然后传递给被调用过程。例如,funct()函数定义如下:
赋值语句“float x=funct(5.6);”在函数调用传递实参5.6时,必须将浮点数5.6强制类型转换为int型数据5传递给形参r,在执行funct()函数中的return语句时,参数5又必须转换为浮点数类型进行表达式计算,计算出的浮点数结果31.4必须再转换为返回值类型数值31,最后还必须将int型数值31转换为float型数再赋给变量x。由此可见,在这条赋值语句执行过程中,进行了4次类型转换。
5.函数的原型声明和函数的定义有什么区别?
答:程序中每个有名字的对象(如变量、函数)都需要有一个唯一的定义和若干处对其引用。为了保证定义和引用一致,通常应先定义后引用。在C语言中,定义和声明是两个不同的术语,定义用于构建一个对象,意味着在编译器转换得到的机器级代码中需要为这个对象分配存储空间,而声明则是说明存在相应的对象,即被声明的对象一定存在一个唯一的定义。如果一个声明的对象没有定义,意味着该声明无效,在生成可执行文件的过程中会出现链接错误。
一个C语言程序可以由多个C源程序文件组成,一个函数通过函数调用语句引用其他函数,每个函数定义中可能有多个函数调用语句。若被调用函数在引用前无定义,则须在引用前给出函数原型声明。