最近招聘季,看JULY大哥的面试100题时,碰到这么一个扩展问题:

如何用一个语句判断一个整数是不是二的整数次幂?(此题在编程之美也有)

  easy, 2的整数次幂的二进制形式只有一个1,只要用i和i-1按位相与,结果为零就说明是:

int i;

bool b = (i&(i-1))?false:true;

(===============只想知道这道题的解法的看到这里就够了,以下都是无关内容===============)

  再下一步之前,请思考一个问题:printf("%d", sizeof('a');的输出是什么?测试验证你的想法后,带着疑问向下看吧。

 

  为了简单验证算法的正确性,我写了如下代码:

typedef short bool

int main()
{
char c = ;
int i = ; while(i<)
{
bool b = c&c-;
printf("%d : c = %d , b = %d\n", i, c, b); i++;
c<<=;
}
return ;
}

  输出

1: c = 1 , b = 0
2: c = 2 , b = 0
3: c = 4 , b = 0
4: c = 8 , b = 0
5: c = 16 , b = 0
6: c = 32 , b = 0
7: c = 64 , b = 0
8: c = -128 , b = -256
//博客机跟开发机不是一台,还不能互联, 纯手打;

  

  好像有什么奇怪的东西混进来了,当1在第8位上的时候, c与c-1按位相与的值变成了-256,简单思考知道这里发生了类型提升:

c = 0x80 = 1000 0000b = -128;

c - 1 提升至 int 型,变为 -129 = (int)0x ff ff ff 7f = (0x ff ff ff)0111 1111b

所以 c&(c-1)的结果为(short)0x ff ff ff 00 = -256

而(char)(c-1) = (char)0xff ff ff 7f = 0111 1111b = 127, 其二进制表示正好与c的互补。

  于是可以将代码修改一下:

bool b = c&(char)(c-1);

  

  由此得出了正确的结果。遗留两个问题:

1.对于int型的值是否也会出现同样问题呢?

2.C语言的类型提升发生在什么时候?

  对于问题1,答案是否定的,这一点可以通过简单试验得知,原理参见问题2的研究:

int apple = 1;
apple <<= 31;
int pear = apple & apple-1;

  

  首先,printf("%d", sizeof('a');的输出是什么?(摘自C专家编程)

答案不是1,而是4(你编译器里int的长度),原因是这里发生了类型提升。

The C Programming Language里的五句真言:

  如果没有无符号的操作数,则有:

  1. 若存在long double的操作数, 则将其他操作数提升为long double。

  2. 否则,若存在double的操作数, 则将其他提升为double。

  3. 否则, 若存在float, 则提升为float。

  4. 否则, 将char和short提升为int。

  5. 然后, 若有long的操作数, 则将其他提升为long。

原文如下:

  If there are no unsigned operands, however, the following informal set of ules will suffice:

  1. If either operand is long double, convert the other to long double.

  2. Otherwise, if either operand is double, convert the other to double.

  3. Otherwise, if either operand is float, convert the other to float.

  4. Otherwise, convert char and short to int.

  5. Then, if either operand is long, convert the other to long.

  而对于unsigned操作数的情况下,则较为复杂,大致上记住无符号与有符号共存时,会向无符号提升。简单建议不要有符号无符号混用。

详细转换规则请参见The C Programming Language;而有符号无符号混用编程可能导致的问题,请参见深入理解计算机系统(广受好评的:CSAPP)。

  

  事实上,有了上面的五句真言,我们就可以了解答之前的问题了:

1.printf("%d", sizeof('a'); //在表达式中,每个char都被转换为int,所以sizeof表达式计算的是:sizeof((int)'a'),其答案为4也就不足为奇;

2.对于文首提出的面试题,int型的值是否也会出现同样问题呢?//答案是不会,因为表达式c&(c-1)中不存在类型提升;

3.C语言的类型提升发生在什么时候?//发生在类型混用的时候,存在char的表达式中一定存在类型转换。

=========================引用===========根据引用顺序=========================

JULY的面试100题(感谢JULY大哥的无私奉献精神):http://blog.csdn.net/v_july_v/article/details/6870251

C专家编程:http://book.douban.com/subject/2377310/

The C Programming Language:http://book.douban.com/subject/1139336/

Computer Systems : A Programmer's Perspective (second edition)(别犹豫,快去买一本): http://book.douban.com/subject/5333562/

  

如何用一个语句判断一个整数是不是二的整数次幂——从一道简单的面试题浅谈C语言的类型提升(type promotion)的更多相关文章

  1. R语言 如何用IF语句判断 一个数字的奇偶

    jishu <- function(x){ ifelse(x%%2 ==0,F,T)}  

  2. 判断一个Activity 判断一个包 是否存在于系统中 的方法

    判断一个包是否存在于系统中(来自网络),经过测试,好用: public boolean checkBrowser(String packageName) { if (packageName == nu ...

  3. 如何用C#代码判断一个类的类型

     var s = "";  s.GetType().IsClass; 来自为知笔记(Wiz)

  4. 博客志第一天——判断一个整数N是否是完全平方数?

    关注博客园很久,今天是第一次写博客.先附上一个C题目:写一个函数判断一个整数是否为完全平方数,同时是否该数的各位数至少两个相同的数字 #include <stdio.h> #include ...

  5. JavaScript —— 如何判断一个非数字输入

    在页面里,如何用JS去判断一个用户输入是不是一个数字. 你是不是首先想到了正则表达式? JS里有个现成的函数,isNaN(x) isNaN(x) 函数可用于判断其参数是否是 NaN(Not a Num ...

  6. Js判断一个单词是否有重复字母

    今天上午刷到一道题,大体是写一个方法判断一个单词中是否有重复的字母(或者说一个字符串中是否有重复的字符).我的思路是一个字符一个字符地遍历,如果发现有重复的停止: function isIsogram ...

  7. Python判断一个字符串中是否存在多个子串中的一个

    在使用python的开发过程中,常常需要判断,字符串中是否存在子串的问题, 但判断一个字符串中是否存在多个字串中的一个时,如if (a or b) in c或者if x contains a|b|c| ...

  8. ZOJ Problem Set - 1331 Perfect Cubes 判断一个double是否为整数

    zju对时间要求比较高,这就要求我们不能简单地暴力求解(三个循环搞定),就要换个思路:因为在循环时,已知a,确定b,c,d,在外重两层循环中已经给定了b和c,我们就不用遍历d,我们可以利用d^3=a^ ...

  9. C语言:判断t所指字符串中的字母是否由连续递增字母组成。-判断一个输入的任何整数n,是否等于某个连续正整数序列之和。-将一副扑克牌编号为1到54,以某种方式洗牌,这种方式是将这副牌分成两半,然后将他们交叉,并始终保持编号1的牌在最上方。

    //判断t所指字符串中的字母是否由连续递增字母组成. #include <stdio.h> #include <string.h> void NONO(); int fun( ...

随机推荐

  1. 查GDI对象泄露的利器:GDIView

    查GDI对象泄露的利器:GDIView可以很详细的查到进程的GDI对象的总个数,详细的GDI对象的个数,以及其增减数量.其GDI对象类型也可以很详细的得知,以及其内存地址,句柄.实在是好使! 下载地址 ...

  2. python 在 for i in range() 块中改变 i 的值的效果

    先上一段代码: for i in range(3): i = 2 print(i) 实际结果是: 2 2 2 可以发现实际效果就是 在每次执行 for 语句块的内容后 i 会被重新赋值

  3. makefile简单helloworld

    最近要在unix系统上开发c++应用程序,但默认情况下unix编译c++程序需要使用makefile.其实makefile语法还是比较简单,看上去有点像ant.废话不说了,直接上helloworld. ...

  4. mongoose查询特定时间段文档的方法

    db.collection.find({ time:{ "$gte": new Date('2014-01-24'), "$lte":new Date('201 ...

  5. 解决Agent admitted failure to sign using the kye with ssh

    之前如果建立 ssh 连接,只要將公匙复制到~/.ssh/authorized_keys就可以直接登录而不需要建立密碼. 如果在使用时候出现如下信息: Agent admitted failure t ...

  6. CF#52 C Circular RMQ (线段树区间更新)

    Description You are given circular array a0, a1, ..., an - 1. There are two types of operations with ...

  7. Activity切换动画(overridePendingTransition)-翻页效果

    Activity的切换动画指的是从一个activity跳转到另外一个activity时的动画.{它包括两个部分:一部分是第一个activity退出时的动画:另外一部分时第二个activity进入时的动 ...

  8. HDU 4861 Couple doubi(找规律|费马定理)

    Couple doubi Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit ...

  9. ADO.NET知识的运用一(Day 26)

    哈哈,又到了总结的时间了,来回顾一下今天主要学了关于ADO.NET的哪些知识吧.(这次学的ADO访问数据库主要以访问SQL数据库为主) 理论:  首先我们要知道为什么要学习ADO.NET? 因为我们之 ...

  10. BZOJ 2064: 分裂( 状压dp )

    n1+n2次一定可以满足..然后假如之前土地集合S1的子集subs1和之后土地集合S2的子集subs2相等的话...那么就少了2个+操作...所以最后答案就是n1+n2-少掉的最多操作数, 由状压dp ...