C-类型转换(陷阱)
getchar() 返回值为int类型
1.自动类型转换(运算符两边变量类型不同时)
1).两个变量类型自动转换成一样的类型(会根据参数类型自动转换, 而不是直接位转换), 且运算结果也是转换后的类型
2).当较低类型的数据转换为较高类型时, 一般只是形式上有所改变, 而不影响数据的实质内容, 而较高类型的数据转换为较低类型时则可能有些数据丢失
3).在进行自动类型转换的时候, 如果原来的数是无符号数, 那么在扩展的时候, 高位填充的是0, 如果是有符号数, 那么高位填充的时符号位
#include <stdio.h> int main() {
unsigned int a = ;
if (a > -) printf("8>-1\n");
else printf("8<=-1\n");
return ;
}
输出结果是8<-1, 明明赋值为8的变量i, 结果被程序判定比-1还小, 这是怎么回事?
问题根源在于变量i定义中的unsigned; 我们都知道, int/short/char等类型分signed和unsigned, C的表达式中signed和unsigned混合运算有三种情况:
a.操作数全为signed
b.操作数全为unsigned
c.操作数混合了signed和unsigned
前两种情况,相同符号操作没什么问题, 可情形c.涉及不同符号间的混合计算就要注意, 编译器会自动对操作数进行规整化:只要表达式中存在一个无符号数, 所有操作数都被转化为无符号数, 运算按相应无符号操作符进行, 计算结果也是一个无符号数(结论:运算时变量会自动转换, 且计算结果同转换后的类型)
为防止意外转换, 一方面要显式指定类型, 不要用int, char这种缺少提示的中性表示法, 这种含糊的表示用多了, 会本能地忽略和回避符号问题; 另一方面要谨慎选用unsigned型, 不要仅仅因为无符号数没有负值就用它表示数量, 比如有人喜欢用unsigned int定义for/while循环计数量, 这很不安全, 一不小心在循环内和负数做比较, 就会发生逻辑错误或死循环; 最后, 如果非要让unsigned型参与计算, 可以用强制类型转换保证中间操作数和结果为signed
2.赋值中的类型转换, 当赋值运算符两边的运算对象类型不同时, 将要发生类型转换, 转换的规则是: 把赋值运算符右侧表达式的类型转换为左侧变量的类型, 具体的转换如下:
1).浮点型与整型
将浮点数(单双精度)转换为整数时, 将舍弃浮点数的小数部分, 只保留整数部分
将整型值赋给浮点型变量, 数值不变, 只将形式改为浮点形式, 即小数点后带若干个0
注意:赋值时的类型转换实际上是强制的
2).单、双精度浮点型
由于C语言中的浮点值总是用双精度表示的, 所以:
float型数据只是在尾部加0延长为doub1e型数据参加运算, 然后直接赋值
doub1e型数据转换为float型时, 通过截尾数来实现, 截断前要进行四舍五入操作
3).char型与int型
int型数值赋给char型变量时, 只保留其最低8位, 高位部分舍弃
char型数值赋给int型变量时, 一些编译程序不管其值大小都作正数处理, 而另一些编译程序在转换时, 若char型数据值大于127, 就作为负数处理; 对于使用者来讲, 如果原来char型数据取正值, 转换后仍为正值;如果原来char型值可正可负, 则转换后也仍然保持原值, 只是数据的内部表示形式有所不同
4)int型与long型
long型数据赋给int型变量时, 将低16位值送给int型变量, 而将高16 位截断舍弃(这里假定int型占两个字节)
int型数据送给long型变量时, 其外部值保持不变, 而内部形式有所改变
5)无符号整数
将一个unsigned 型数据赋给一个占据同样长度存储单元的整型变量时(如:unsigned→int、unsigned long→long,unsigned short→short), 原值照赋, 内部的存储方式不变, 但外部值却可能改变
将一个非unsigned整型数据赋给长度相同的unsigned型变量时, 内部存储形式不变, 但外部表示时总是无符号的
计算机中数据用补码表示, int型量最高位是符号位, 为1时表示负值, 为0时表示正值; 如果一个无符号数的值小于32768则最高位为0, 赋给int型变量后、得到正值; 如果无符号数大于等于32768, 则最高位为1, 赋给整型变量后就得到一个负整数值; 反之, 当一个负整数赋给unsigned 型变量时, 得到的无符号值是一个大于32768的值, (这里假定int型占两个字节)
C语言这种赋值时的类型转换形式可能会使人感到不精密和不严格, 因为不管表达式的值怎样, 系统都自动将其转为赋值运算符左部变量的类型, 而转变后数据可能有所不同, 在不加注意时就可能带来错误, 这确实是个缺点, 也遭到许多人们批评, 但不应忘记的是:C面言最初是为了替代汇编语言而设计的, 所以类型变换比较随意, 当然, 用强制类型转换是一个好习惯, 这样, 至少从程序上可以看出想干什么
3.强制类型转换
对于从高到低的强制转换, 实质上就是一个截断的操作, 只把低端需要的部分保留, 其余的部分直接扔掉了
2.printf 就是按照什么类型去打印一串010101010111(把数据转换成可显示的形式), 不会进行类型转换, 如果类型不同则会显示垃圾值(float, double都是用%f, %e, %a, 因为当它们向那些未在原型中显式说明参数类型的函数(比如printf)传递参数时, C自动将float类型参数转为double类型(8个字节, 所以用%f打印int, 后面四个字节是随机的))
#include <stdio.h> int main() {
float n1 = 3.0;
float n2 = 3.0;
long n3 = ;
long n4 = ;
printf("%ld %ld %ld %ld\n", n1, n2, n3, n4);
return ;
}
以上程序输出0 1074266112 0 1074266112
4.scanf 类型不一致 可以得到数据 但是不一定正确
5.函数参数中的类型转换, 相当于赋值操作的自动转换
看下没有用函数原型的参数类型的例子:
#include <stdio.h>
int imax();int main(void) {
printf("The maximum of %d and %d is %d.\n", , , imax());
printf("The maximum of %d and %d is %d.\n", , , imax(3.0, 5.0));
return ;
} int imax(int m, int n) {
return m > n ? m : n;
}
输出
The maximum of 3 and 5 is 1245120.
The maximum of 3 and 5 is 1074266112.
调用函数首先把参数放在一个称为堆栈的临时存储区, 然后被调函数从堆栈中读取这些参数, 但是这两个过程没有相互协调进行, 调用函数根据调用过程中的实际参数类型确定需要传递的数值类型, 但是被调函数时根据 其形式参数的类型进行读取数据的, 因此, 函数imax(3)把一个整数放在堆栈中, 当函数imax()开始执行时, 它会从对战中读取两个整数, 而实际上只有一个需要的数值被存储在堆栈中, 所以第二个独处的数据就是当时恰好在堆栈中的其他数值
第二次使用函数imax()时, 传递的是float类型的数值, 这时两个double类型的数值就被放在对战中, 而系统中意味着两个64位的数值, 即共128位的数据存储在堆栈中, 因为这个系统中的int类型是32位, 所以当imax()从对战中读取两个int类型的数值时, 它会读出对战中前面64位的数据, 把这些数据对应于两个整数
更正:把int imax()原型声明改为int imax(int a, int b);
使用函数原型, 编译器就可以检查函数调用语句是否和其原型声明相一致, 比如检查参数个数是否正确, 类型是否匹配, 如果有一个参数类型不匹配但都是数值类型, 编译器会把实际参数值转换成和形式参数类型相同的数值
6.函数return中的类型转换, 相当于赋值操作的自动转换
如果实际返回值与函数定义的返回类型不同, 则会自动转换成函数定义的返回类型, 然后再返回
7.
1).类型自动提升 2).多种类型参加运算, 类型自动转换 3).赋值转换 参考:http://blog.csdn.net/zhuyi2654715/article/details/7782872
. 如果有一边的类型是long double, 则把另一边也转成long double
. 否则, 如果有一边的类型是double, 则把另一边也转成double
. 否则, 如果有一边的类型是float , 则把另一边也转成float
. 否则, 两边应该都是整数类型, 首先按上一小节讲过的规则对a和b做Integer Promotion, 然后如果类型仍不相同, 则需要继续转换 首先规定char 、short 、int 、long 、long long 的转换级别(Integer Conversion Rank)一个比一个高, 同一类型的有符号和无符号数具有相同的Rank, 然后有如下转换规则:
a. 如果两边都是有符号数, 或者都是无符号数, 那么较低Rank的类型转换成较高Rank的类型 例如unsigned int 和unsigned long 做算术运算时都转成unsigned long
b. 否则, 如果一边是无符号数另一边是有符号数, 无符号数的Rank不低于有符号数的Rank, 则把有符号数转成另一边的无符号类型 例如unsigned long 和int 做算术运算时都转成unsigned long , unsigned long 和long 做算术运算时也都转成unsigned long
c. 剩下的情况就是:一边是无符号数另一边是有符号数, 并且无符号数的Rank低于有符号数的Rank 这时又分为两种情况, 如果这个有符号数类型能够覆盖这个无符号数类型的取值范围, 则把无符号数转成另一边的有符号类型 例如遵循LP64的平台上unsigned int 和long 在做算术运算时都转成long
d. 否则, 也就是这个符号数类型不足以覆盖这个无符号数类型的取值范围, 则把两边都转成两者之中较高Rank的无符号类型 例如遵循ILP32的平台上unsigned int 和long 在做算术运算时都转成unsigned long
C-类型转换(陷阱)的更多相关文章
- 心动不如行动,基于Docker安装关系型数据库PostgrelSQL替代Mysql
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_171 最近"全栈数据库"的概念甚嚣尘上,主角就是PostgrelSQL,它最近这几年的技术发展不可谓不猛,覆盖 ...
- C# 类型转换is和as 以及性能陷阱
1.在C#2.0之前,as只能用于引用类型.而在C#2.0之后,它也可以用于可空类型.其结果为可空类型的某个值---空值或者一个有意义的值.示例: static void Main(string ...
- c++隐式类型转换存在的陷阱
目录 目标代码 构造函数定义的隐式类型转换 分析a1 分析a2 分析a3 目标代码 旨在弄懂下面的代码,明确变量a1,a2,a3在创建时编译器究竟干了那些事: #include<iostream ...
- C语言陷阱——类型转换
以下例子取自<深入理解计算机系统>. 考虑如下的C语言代码: #include<stdio.h> typedef unsigned char* byte_pointer; vo ...
- JavaScript的陷阱
这本来是翻译Estelle Weyl的<15 JavaScript Gotchas>,里面介绍的都是在JavaScript编程实践中平时容易出错或需要注意的地方,并提供避开这些陷阱的方法, ...
- Delphi初学者应小心的六大陷阱
Delphi初学者应小心的六大陷阱 作者:子夜编译 初学DelphiI的人,由于各种原因,对DelphiI中的许多概念不能很好的理解,并由此带来了许多的问题,或者是开发出的程序稳性不好 ...
- 《C陷阱与缺陷》读书笔记
1. 词法“陷阱” = 不同于 == , 可以通过if( 1 == a )来避免 & | 不同于 && || 词法分析中的“贪心法” 编译器将程序分解成符号的方法是,从左到右一 ...
- 可变长参数列表误区与陷阱——va_arg不可接受的类型
可变长参数列表误区与陷阱--va_arg不可接受的类型 实现一个有可变长参数列表函数的时候,会使用到stdarg.h(这里不讨论varargs.h)中提供的宏. 例如,我们要实现一个简易的my_pri ...
- 【JavaScript】JavaScript中的陷阱大集合
本文主要介绍怪异的Javascript,毋庸置疑,它绝对有怪异的一面.当软件开发者开始使用世界上使用最广泛的语言编写代码时,他们会在这个过 程中发现很多有趣的“特性”.即便是老练的Javascript ...
- java之表达式陷阱
String str1 = "Hello Java的长度:10"; String str2 = "Hello Java的长度:10"; String str3 ...
随机推荐
- python带cookie提交表单自动登录
import urllib import urllib2 import cookielib login_url = "xxxxxxxxxxxxx" cj = cookielib.C ...
- Spark部署及应用
在飞速发展的云计算大数据时代,Spark是继Hadoop之后,成为替代Hadoop的下一代云计算大数据核心技术,目前Spark已经构建了自己的整个大数据处理生态系统,如流处理.图技术.机器学习.NoS ...
- 备份文件的python脚本(转)
作用:将目录备份到其他路径.实际效果:假设给定目录"/media/data/programmer/project/python" ,备份路径"/home/diegoyun ...
- ubuntu fcitx google 输入法打不出中括号【】
编辑/usr/share/fcitx/data/punc.mb.zh_CN, 将 [ · ] 「 」 这部分改成自己习惯的: [ [ ] ] 保存后,重启一下fcitx就OK了.
- Codeforces #428 Div2 D
#428 Div2 D 题意 给出一些数,现在要求找出一些数满足 \(i_1 < i_2 < i_3 < ... < i_k\) 以及 \(gcd(a_{i_1}, a_{i_ ...
- csu1216( Trie )
csu1216 题意 给定一些数,求这些数中两个数的异或值最大的那个值. 分析 转化成二进制数存入字典树,比如说要查询 \(0011\) ,显然和 \(1100\) 结合最优,所以我们直接在字典树上寻 ...
- 一种可以做app性能监控的app
http://easytest.taobao.com/?spm=0.0.0.0.ljgQHN
- CodeChef - UASEQ Chef and sequence
Read problems statements in Mandarin Chinese and Russian. You are given an array that consists of n ...
- 【模拟】bzoj2760 [JLOI2011]小A的烦恼
注意细节和初始化. #include<cstdio> #include<string> #include<algorithm> #include<iostre ...
- Problem D: 零起点学算法40——多组测试数据(求和)IV
#include<stdio.h> int main() { int n,i,sum,a; ) { sum=; ;i<=n;i++) { scanf("%d",& ...