面试问题
昨天我在采访中被问到了下面代码的输出
#include <stdio.h> int main(void){ printf ("%x" ,-1<<4); }
我被给了2分钟来说出答案。 我回应了fffffff0
。 采访的结果还没有被宣布。 我想知道我的答案是否正确?
技术上左移一个负整数将调用未定义的行为。 这意味着-1<<4
是UB。 我不知道他们为什么问你这个问题。 可能他们想testing你对C和C ++标准的深入了解。
C99 [ 6.5.7/4
]说
E1 << E2的结果是E1左移E2位的位置; 空位填充零。 如果E1具有无符号types,则结果的值是E1×2 E2 ,比结果types中可表示的最大值减1。 如果E1具有带符号的types和非负值,并且在结果types中可以表示E1×2 E2 ,那么这是结果值; 否则,行为是不确定的 。
C ++ 03通过省略相关的文本使其不明确的行为。
不,你不对。 这是个坏消息。 好消息是,面试官可能不知道,并会认为你是因为这是他们编译和运行的结果。
真正的答案是它是实现定义的。 我不是100%自信地说这是因为超负荷而未定义的行为,但我认为可能是。 至less结果取决于如何表示负数,等等……你所声称的这两种语言都不是定义输出的结果。
在我的机器上:
chris@zack:~$ cat > test.c #include <stdio.h> int main(void){ printf ("%x" ,-1<<4); } chris@zack:~$ gcc -o test test.c && ./test fffffff0
但是,结果将取决于您的体系结构和编译器。 所以正确的答案是“它可以输出任何东西”。
Binary of 1 : 0000 0000 0000 0000 0000 0000 0000 00001
用你想要计算负号的二进制数来replace0的出现次数
如何计算负数的二进制数
Binary of -1 : 1111 1111 1111 1111 1111 1111 1111 11111 Left shift 4 : 1111 1111 1111 1111 1111 1111 1111 0000
结果左移4的hex表示
1111 : F 0000 : 0
所以计算的输出将是:
FFFFFFF0
你的回答是对的。
左移一个负数对于一般情况是不确定的,但是我们必须理解为什么这个未定义的行为(UB)? 请记住,最高有效位(MSb)是符号位。 如果这个位是1,那么这个数字是负数。 如果它是一个零,这个数字是正数。 这是关键的信息丢失了第一个左移。 例如
-32768<<4
是一样的事情
0x8000<<4
(为了简单起见,假设一个16位的机器)
结果当然是0,这实际上没有任何意义,因此是UB。
在OP的访问问题的具体情况下,我们只关心一个具体的价值… 而不是一般情况。 -1(在32位机器上的0xffffffff)向左移动4次将产生0xfffffff0,正如OP最初所想的那样。
这是未定义的行为。
$ cat undef.c #include <stdio.h> int main(void){ printf ("%x" ,-1<<4); } $ clang -fsanitize=undefined undef.c $ ./a.out undef.c:3:24: runtime error: left shift of negative value -1 fffffff0
我在3个不同的编译器和操作系统上运行这个代码。 所有人都给了我这个问题中提到的同样的答案。 除非有人提出这个编译器的确是一个未定义的行为,否则我会说答案是正确的。 如果这种情况在99.99%的情况下是稳定的,那么标准变得更多的机会比编译器停止支持它更多。
我只是在一个文本文件中编写代码,编译它, 是的 ,答案是正确的。