这道题有“圈套" 基础不好很容易上套!
今天给大家带来一道中国台湾某著名cpu生产公司的面试题。
储备知识
1
要看懂今天的代码需要一点储备知识。
// C语言的符号意义
~ 按位取反 例如 ~(111b)= (000b)
>> 按位右移 例如 (0011b)>>2 = (0000b)
~、>>、+ 的优先级排序 ~ 大于 + 大于 >> 优先级越高的运算符越先执行
2
题目及分析
话不多说上代码:
#include <stdio.h>
int main()
{
unsigned char a = 0xa5;
unsigned char b = ~a>>4+1;
printf("b=%dn",b);
return 0;
}
你算出的结果是什么?
估计大部分的朋友算出的结果都是2。
初步分析
让我们一起来看一下,大致分析这个代码,可以发现这个代码考察了两个知识点:
一是数据类型转换问题
二是运算符的优先级问题
unsigned char b = ~a>>4+1;
上面这行代码,~的优先级最高,首先肯定是对a进行按位取反,然后是+的优先级较高,所以执行4+1 =5,最后执行右移操作。
因此上面的代码等价于:
unsigned char b = [(~a)>>(4+1)] = (-a)>>5 ;
也就是先对a进行逐位取反,~0xa5 = ~ (1010 0101b) = 0101 1010b = 0x5a
再右移5位得到0x2。结果算出来是2?
让我们直接运行代码来查看结果:
怎么回事?答案并不是预期中的2,b忽然等于250!,这是为什么呢?
隐式数据类型转换和整值提升
unsigned char b = ~a>>4+1;
让我们再来仔细观察上面这行代码,发现出现了不同类型之间的运算:a的数据类型是char,4和1的数据类型没有指定,c语言编译器会默认其为int类型。
相信大家都知道,在C语言的运算过程中,如果运算符两边的数据类型不一致,编译器会自动进行隐式数据类型转换。
这种数据类型转换总体来说比较复杂,但是总体遵循这个原则:尽量避免数据精度损失
上面的原则意味着什么呢?
如果运算符两边的数据类型不一致,编译器总是尽量往较宽的数据类型进行转换。
如果计算过程中的计算数不是浮点数,那么他们肯定都是整型,编译器一般会将所有小于int类型宽度的数据类型提升到int,这种现象被称为“整值提升”
进一步分析
unsigned char b = ~a>>4+1;
知道了整值提升,让我们再来重新看看上面这行代码:
a是unsigned char,数据宽度小于 int,所以编译器在对a进行按位取反操作之前,会先将a的数据类型提升至int。
不同机器上,int的数据宽度不同,在我的机器上int的大小是4个字节。
因此将a进行数据类型转换后,a = 0x 00 00 00 a5 ,按位取反以后就是 ~a = 0x ff ff ff 5a,然后再按位右移5位(高位自动补0),得到的就是0x07 ff ff fa ,在将该数值复给b的时候,因为b的数据类型是 char,只有一个字节,因此会发生数据截断,只有最低位字节保留下来了,也就是 0xfa = 250。
总结
通过这道题,大家可以发现,如果对c语言的隐式数据类型转换不熟悉,就很容易上套。
另外,运算符的优先级还是比较难记的,建议还是使用括号明确执行顺序。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Jupyter 插件太好用了
- 华为提出十大数学挑战!解出一个就是年薪百万!
- 一道 Google 的面试题
- 生产实践 | 基于 Flink 的短视频生产消费监控
- 图数据库调研
- Swift 类构造器的使用
- 「网络IO套路」当时就靠它追到女友
- 起个简单枯燥的标题:找出连续差相同的数字
- 10分钟带你搞懂代理模式、静态代理、JDK+CGLIB动态代理
- 握草!某程序员竟然在深夜偷偷在代码里下毒!
- 自然资源部贡献的Landuse数据(2000、2010、2020)
- LoRa节点开发——SDK整体设计思路
- 01 . Nginx简介及部署
- 02 . Nginx平滑升级和虚拟主机
- LoRa节点开发——LoRaWAN节点入网代码详解