C语言中的类型转换

C语言中的类型转换有两种,自动与强制。

它们都有几种情况,如不同长度的转换;不同类型的转换;还有无符号与有符号数之间的转换。关键是两点,即长度不同时如何转换,在有无符号数参与时如何转换。

一般的处理方式是长变短时作一个简单的截短操作,内存的对齐方式影响这个结果。短的变长时,与符号有关,如果是有符号数,则有两种可能,符号扩展或简单地提升(即高位补0)。这个C标准没有定义,取决于编译器。所以,在将短的数据转换为长的数据时,最好是用强制的转换。无符号数就没关系了,结果是一样的。

1.强制类型转换

具体形式如下:

(类型)表达式

这个出错的机会比较小一点,因为由程序员自己控制。但要注意的,在对指针转换时,如果将一个

指向一个较小内存单元的指针转换为一个指向较大内存单元的指针,就会破坏其它内存单元的数据。

这个在自动转换中也有,故在下面一起描述。强制转换一般是在将一个空指针赋给一个在类型的指针

时的操作,如在malloc()操作时。

2.自动类型转换

这是最容易出错的,因为C语言对类型的检查比较少,这样设计的好处是给程序员提供编程上的方便,但任何事情都有两面性,自动类型转换有不少副作用。我们先来看一下自动转换在什么时候发生:

1)表达式求值

2)赋值

3)函数调用

这几种转换的细节都可以参考《C程序设计语言》(The C Programming Language, Brian

W.Kernighan, Dennis M.Ritchie)

一是有无符号数参与的表达式计算

C语言中对这个没有规定,取决于实现。看下面这个例子:

#include

int main(void)

{

long a;

unsigned short b;

unsigned long c, d;

short e;

a = -1L;

b =   1U;

d = a + b;

printf("a = %dL, b = %uU, d = %uUL, a>b = %d\n",a, b, d, a > b);

a = -1L;

c = 1UL;

d = c + a;

printf("a = %dL, c = %uUL, d =%uUL, a>c = %d\n", a, c, d, a > c);

e = -1;

c =   1UL;

d = e + c;

printf("e = %d, c = %uUL, d =%uUL, e>c = %d\n", e, c, d, e> c);

}

运行结果如下(在我的环境中compaq Tru64, cc)

a = -1L, b = 1U, d = 0UL, a>b = 0

a = -1L, c = 1UL, d =0UL, a>c = 1

e = -1, c = 1UL, d =0UL, e>c = 1

我们不难发现,在比较操作中,将无符号的短整数扩展为了有符号的长整型。所以有-1L < 1U;又将有符号的短整数提升为了无符号的长整型,所以有-1 > 1UL;还将相同长度的两个数的有符号的长整数转换为无符号的长整数,所以有-1L > 1UL。所以,这里的规则似乎是在类型长短不一时,以较长的为准,长度相同时,有符号的转化为无符号的,但也仅仅是比较操作,其它呢?还是要看实现。在加法操作中,不管数据的长短,一律作为有符号数计算,实际上有符号有无符号的加减法结果是一样的,这里一样指的是操作后变量在内存中的二进制串是一样的,只是它作为有符号数还是无符号数展示而已。所以上例中d始终是0。

为了证明在不同的环境下结果不同,我又在windows下,用Turbo C运行了一下,结果如下:

a = -1L, b = 65535U, d = 1UL, a>b = 0

a = -1L, c = 65535UL, d =1UL, a>c = 0

e = -1, c = 1UL, d =0UL, e>c = 0

这就意味着你编程时要特别注意,在使用前要测试一下你的环境对这个是如何处理的,也就意味你的代码是不可移植的。所以一条很重要的编程规则就是,尽量避免使用无符号数。

二是在函数的调用中的自动类型转换。

C语言中,在将实参传给函数时,如果类型不匹配,会进行自动类型转换。如果在函数声明时没有给出参数列表,则C编译器会认为不知道参数是什么,不进行类型检查,这样可能会导致错误的函数调用。C语言的类型检查也不是太严格,甚至警告也不会给就自动转换了。无参数的则要么提升,要不就原样拷贝。这里,原样拷贝比提升安全,因为有类型检查,所以在函数内部没有转换。

在ANSI C标准之前,处理比较复杂,声明不能有形参,要是一个空列表,而且,调用时,会将单精度转换为双精度的,将short, char转换为int。那这样就有一个问题了,如果函数确实需要一个char怎么办呢?办法是在定义的内部转换。也就是形参全部用int或double型表示,然后在内部定义相应需要类型的局部变量,在内部来一个赋值的再转换,显然这种方法比较笨。但许多编译器为了与老版本兼容,还是采用的这种方式,在函数声明中,不强制要求写出参数列表,调用时也不作类型检查。然后在函数内部转换。当然,还一种方式就是不作任何类型检查,完全取决于程序员,这是最危险的方法。

这些都取决于编译器。

函数的返回值也要注意,如果没有显式的声明,则默认为int,对某些调用会出错。因为调用程序会按照默认的类型来取返回值,这样,如果返回值的类型不是这样,就极有可能得到一个错误的结果。返回值的存储地点由编译器决定,一般通过寄存器来实现。

这些问题本质上都是由于类型的转换引起的,C语言对类型的检查不那么严格,所以容易引起许多潜在的错误。

下面给一个例子说明一下:

#include

typedef struct tag_data

{

char c1;

char c2;

char c3;

char c4;

}DATA, *PDATA;

int main(void)

{

DATA adata = {-1, 'a', 'b', 'c'};

int iret = -1;

printf("Enter a charactor\n");

iret = scanf("%d", &adata.c1);

printf("iret = %d, adata.c1 = %c, adata.c2 = %c, adata.c3 = %c, adata.c4 = %c\n", iret, adata.c1, adata.c2, adata.c3, adata.c4);

printf("iadata.c1 = %d, adata.c2 = %d, adata.c3 = %d, adata.c4 = %d\n", adata.c1, adata.c2, adata.c3, adata.c4);

return 0;

}

运行结果如下:

Enter a charactor

a

iret = 0, adata.c1 = , adata.c2 = a, adata.c3 = b, adata.c4 = c

adata.c1 = -1, adata.c2 = 97, adata.c3 = 98, adata.c4 = 99

再一次运行如下:

Enter a charactor

2048

iret = 1, adata.c1 = , adata.c2 =, adata.c3 = , adata.c4 =

adata.c1 = 0, adata.c2 = 8, adata.c3 = 0, adata.c4 = 0

我们看到,第一次运行,结果与我们设想的不一样,从scanf的返回值可以看到,它运行出错了,因为它需要一个整型!所以给它一个字符型变量,它就报错返回了。第二次运行,结构体中的c2,c3,c4全部改变了,这是为什么?因为在scanf中,我们使用的%d,这样,scanf在读到%d的时候,它就判定,与此对应的参数为一个指向整型的指针,它在读到一个数后会将它存到这个指向所指向的区域之中,我们知道,32位的机器上整型占四个字节,所以读入的这个数就会存放在这个指针所指向的地址起的四个连续字节中 ,而恰好这四个字节编译器分配给了结构体变量adata,所以其它的数据就被破坏了。第一次运行时没有写内存就出错返回了,所以并没有改写,这也是为什么c2,c3,c4的输出还是原来所赋的初始值的原因。这里实际上就是把一个指向小内存单元的指针给了一个需要大内存单元的对象时产生的后果。至于这个指针破坏那些数据,要看它附近的内存空间分配给了哪些变量,而这个又是与机器的体系结构,编译器的实现有关的。

最后要说明的是,不同的编译器与环境对这个处理也是不同的。如在Trubo C中,运行如下:

Enter a charactor

2048

iret = 1, adata.c1 = , adata.c2 =, adata.c3 = b, adata.c4 = c

adata.c1 = 0, adata.c2 = 8, adata.c3 = 98, adata.c4 = 99

这是因为它把int当成2个字节,虽然在32位的机器上,windows平台下。

所以,我们总结一下,要保证类型安全我们应该注意什么

1)要有类型安全的意识

编程时要时刻警惕,否则一不小心,出了问题想半天也找不出问题出在哪里。

2)避免将长类型的变量赋给短类型的变量

这样会造成由于短类型的容量有限造成信息丢失。

3)避免将小内存的指针赋给一个需要大内存指针的对象

原因上面说了。

4)尽量避免使用无符号数。

这个不是绝对的,一般它在如下情况中使用,将一个有符号的短类型转换为长类型时,先强制转换该数据为无符号的,再进行提升,将之转换为有符号的类型。如char转换为int型时,先用类型(unsigned char)强制转换一下,再转换为整型。

5)记住没有无符号数时的自动转换规则

c语言强制类型转换成整形,C语言强制类型转换相关推荐

  1. c语言177转换成八进制,C语言项目设计——进制转换

    <河海大学C语言项 目设计> 课程设计题目: 进制转换系统 学生学号: 学生姓名: 指导老师: 一.程序功能 本系统由c语言编写而成,主要实现对进制的转换.输入一个数,按要求转化成二进制, ...

  2. c语言字符串转成二进制,C语言中字符串如何转换为二进制、八进制、十进制、十六进制...

    在C语言某个程序当中需要把文本16进制转换成对应的16进制数,比如字符串"0x1a"转换成10进制的26,可以用以下函数来实现 相关函数: atof, atoi, atol, st ...

  3. php强制转成字符串,php怎么强制转成字符串

    php强制转成字符串的方法:首先创建一个PHP示例文件:然后定义一个变量:最后通过PHP中的string方法强制转换成字符串即可. 本文操作环境:windows7系统.PHP7.1版,DELL G3电 ...

  4. c语言程序设计胡成松,C语言程序设计教学课件 作者 胡成松 黄玉兰 李文红 课后习题解答 习题答案 4选择结构程序设计 .docx...

    C语言程序设计教学课件 作者 胡成松 黄玉兰 李文红 课后习题解答 习题答案 4选择结构程序设计 .docx (3页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方 ...

  5. c语言330转化成字符,c语言同步练习(330份).doc

    c语言同步练习(330份) 第一章计算机基础 易错题型分析 C语言的基本单位是() A 函数B过程C子程序D子例程 答案:(A) [分析考点] C语言是函数式的语言,它的基本单位是函数,在C语言中任何 ...

  6. C语言答案写成科学记数法,c语言科学记数法_C语言中、科学计数法123456e+002具体代表什么意思、或者说怎么理解这个数_淘题吧...

    『壹』 c语言用double写了一个表示科学计数法的程序,但是却读不出来30位以上的数,怎么办 double 是抄64 位(8字节),52 位代表有袭效数位,11 位表示指数,一位表示符号,精度(有效 ...

  7. c语言存储大范围整形,C语言整形数值范围问题

    有符号二进制数的表示是这样的:如果计算机的字长为n位,n位二进制数的最高位为符号位.其余n-1位为数值位,采用补码表示法时,可表示的数X的范围是 -2的(n-1)次幂 <= X <= 2的 ...

  8. c语言char数字转int补位,关于char强制转换成int到底是用0还是用1补位的猜想与检验...

    关于char强制转换成int到底是用0还是用1补位的猜想与检验 最近学C语言发现char强制转换时值会完全不同,而且变化很大,于是决定写代码测试一下. 先检验一下char型的-3和3在内存中分别怎么表 ...

  9. c语言不通类型指针转换,C语言之强制类型转换与指针--#define DIR *((volatile unsigned int *) 0x0022)...

    强制类型转换形式:(类型说明符) (表达式) 举例说明:1) int a; a = (int)1.9; 2)char *b; int *p; p = (int *) b; //将b的值强制转换为指向整 ...

  10. c语言整数除法转换成浮点型,C语言中的类型转换

    在C语言中不同类型的数据也可以使用二元运算符进行运算,不过如果不明白其中的规律的话,编出来的程序就会有些危险了. 强制类型转换 自动转换类型 举个例子: /*测试数据的类型转换*/ #include ...

最新文章

  1. 免费使用《Autorun病毒防御者》
  2. 多元化谋定美国农业巨头-丰收节贸易会:四大粮商曲折历程
  3. C#中的变量、常量、数据类型
  4. python进阶之学习笔记_干货 | Python进阶系列之学习笔记(四)
  5. java io系列09之 FileDescriptor总结
  6. CentOs中iptables配置允许mysql远程访问
  7. P(A)P(B|A)=P(B)P(A|B)
  8. spring.net与OracleODP结合时发生的版本问题
  9. 如何关闭父窗体?C#(已解决)
  10. Redis 之 简单备份还原
  11. k2 abc 官改固件下载_abc分析,k表示聚类
  12. TM4C123-使用ROM中的函数库
  13. 第三章 微分中值定理及其应用
  14. java tld_Java Web自定义标签tld文件的简单使用
  15. Visual Assist X 10.9 builds 2333 with patch.7z
  16. Win10系统 Office2010程序打开PPT文档报错“此应用无法在你的电脑上运行
  17. Ubuntu 10.4 .安装Cairo-dock
  18. confluence 删除_知识管理平台Confluence教程:如何删除或还原页面?
  19. 信息量理解、信息熵公式的推导
  20. 使用代理服务器导致电脑无法打开网页解决办法

热门文章

  1. linux bind日志级别,Bind日志配置。
  2. 电脑如何打开软键盘,教大家Win10如何打开软键盘的方法
  3. NEO区块链-DAPP开发直通车-第零篇
  4. 《星际迷航*:舰桥船员》与虚拟现实新趋势
  5. 赵小楼《天道》《遥远的救世主》深度解析(36)丁元英为什么参加芮小丹组的那场文化人的饭局?
  6. vivado error:Multiple declarations of unsigned included via multiple use clauses
  7. 2021半年度博客总结
  8. HLS第十二课(bayer photo)
  9. Linux shell爬虫实现树洞网鼓励师(自动回复Robot)
  10. 猎头解密互联网公司offer行情,网易游戏研发高达40W--IT薪资待遇