34

I was asked the output of the following code in my interview yesterday

#include <stdio.h>
int main(void){
       printf ("%x" ,-1<<4); 
}

I was given 2 minutes to tell the answer. I responded fffffff0. The result of the interview has not been declared yet. I want to know was my answer correct?

Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
Girish Mittal
  • 343
  • 3
  • 5
  • 1
    Doesn't that depend on the representation of signed integers? – You Nov 24 '10 at 17:46
  • 41
    Well, there's one way to find out. Compile and run the code, silly! – cdhowie Nov 24 '10 at 17:46
  • 12
    @cdhowie - if you're joking, it's funny but probably not fully apparent to the OP. If you're not, shame on you. – Edward Strange Nov 24 '10 at 18:07
  • In addition to the -1<<4 issue, the program has undefined behaviour because there's no return statement in main (this could have practical implications to the "output" question on some platform - can imagine the clean up code that flushes buffers to stdout at the OS level might not get invoked). – Tony Delroy Nov 25 '10 at 00:45
  • 7
    @Tony: `main` doesn't need a return statement. See http://stackoverflow.com/questions/2637671/ – MSalters Nov 25 '10 at 10:23
  • @MSalters: cool - didn't know C99 had added that... (been using C++ too long to care, which clearly means I should be careful with my comments on C code!). Cheers. – Tony Delroy Nov 25 '10 at 16:32
  • IIRC even prior to C99, dropping off the end of main was not UB but just resulted in indeterminate exit status. – R.. GitHub STOP HELPING ICE Dec 24 '10 at 22:20
  • @R: I think it wasn't UB to not return, but became UB when the (missing) value was actually used. – GManNickG Jan 09 '11 at 08:33
  • "Well, there's one way to find out. Compile and run the code, silly!" -- The code doing something doesn't tell you whether the spec states the something is undefined or implementation-defined. – Swiss Frank Jun 07 '19 at 15:07

8 Answers8

58

Technically left-shifting a negative integer invokes Undefined Behaviour. That means -1<<4 is UB. I dont know why they asked you this question. Probably they wanted to test your depth of knowledge of the C and C++ Standards.

C99 [6.5.7/4] says

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1× 2E2, reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1× 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

C++03 makes it undefined behaviour by omitting the relevant text.

Community
  • 1
  • 1
Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • 24
    Either they wanted to test depth of knowledge, or they just plain don't know. I've been to more than a few interviews where they didn't actually know the correct answer to a technical question. More often than not, especially early stages, the interviewer is HR or management. As I learned, the somewhat hard way, being highly proficient on the technical aspects doesn't help at all in becoming management...can even hurt your chances. And HR...it's just not their area at all. Trick questions like this are often asked by the least knowledgeable...in my experience. – Edward Strange Nov 24 '10 at 18:05
  • 3
    @Noah: Yeah - I remember being told I was wrong about there being such a thing as a `signed char` type when I mentioned it in a response to being asked about the difference between `unsigned char` and plain-old `char`. But that was by a technical lead, not HR or management. – Michael Burr Nov 24 '10 at 18:35
  • I'd need to check, but my understanding of the C standard was that shifting *by* a negative value was indeed undefined, but that shifting *a* negative value was "implementation-defined", i.e. it doesn't have to be the same on all platforms, but it needs to be defined. In any case, on any recent platform, -1<<4 better give -16 or else there's a lot of things that will break (starting with most media codecs). – Jean-Marc Valin Nov 24 '10 at 19:21
  • 5
    @Jean-Marc: Prasoons' answer quotes directly from the C99 standard. Left-shifting a negative value is undefined behavior. However, if *right* shifting a negative value, the result is implementation defined. – Michael Burr Nov 24 '10 at 21:55
  • Prasoon: litb's comment on your "omitting the relevant text" link leads me to think that there's ample room to interpret that snippet as meaning that left-shifting a negative integer is *implementation-defined*, rather than UB. Just saying. – j_random_hacker Jan 09 '11 at 10:08
9

No. You're not correct. That's the bad news. Good news is that the interviewer probably doesn't know that and will assume you are because it's the result THEY get when they compile and run it.

True answer is that it is implementation defined. I'm not 100% confident to say it IS undefined behavior because of the overload, but I think it may be. At the very least though the result is dependent upon how negative numbers are represented, etc... Neither language you've claimed this is in define what the output will be.

Edward Strange
  • 40,307
  • 7
  • 73
  • 125
9

On my machine:

chris@zack:~$ cat > test.c
#include <stdio.h>
int main(void){
       printf ("%x" ,-1<<4);
}

chris@zack:~$ gcc -o test test.c && ./test
fffffff0

However, the result will depend on your architecture and compiler. So the correct answer is "it could output anything."

Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • Compiler output is irrelevant. – Edward Strange Nov 24 '10 at 17:56
  • 1
    Irrelevant, but interesting. Nevertheless, there is nothing about my answer that is incorrect. – cdhowie Nov 24 '10 at 17:58
  • 3
    Not complaining about points (I'm capped anyway, I could care less) but when someone downvotes I usually expect them to leave feedback as to why, so that I have the opportunity to improve my answer. – cdhowie Nov 24 '10 at 18:02
  • 1
    I don't see how compiler output is irrelevant. I would argue that it's more relevant than quoting the standard. Especially when you get the same output for every compiler that anybody cares about. – Benjamin Lindley Nov 24 '10 at 18:05
  • 1
    So I gave you that feedback. Quit complaining about it. – Edward Strange Nov 24 '10 at 18:06
  • 2
    @PigBen compiler output is irrelevant because it is undefined behavior and the result may change for the next release of `` – Praetorian Nov 24 '10 at 18:16
  • 1
    @PigBen: Do you think "works today on my machine" is more relevant than the standard? Compiler output can be interesting but relying on UB can lead to software that's short-lived or fragile under maintenance. – Blastfurnace Nov 24 '10 at 18:26
  • 1
    @Praetorian: It may change, but you know as well as I that it won't, not unless int is extended to 64 bits. And since the question is "What will the output be?" and not "What may the output be?", compiler output is a sensible answer. – Benjamin Lindley Nov 24 '10 at 18:26
  • @Blastfurnace: I would, of course, not rely on UB. I would, of course, not write code like this. But compilers do produce output for that code, so there is an answer. – Benjamin Lindley Nov 24 '10 at 18:28
  • 1
    @PigBen - and you just showed one very good reason why output is irrelevant and doesn't answer the question. The question, at least as expressed by the OP, does not specify what compiler, version, architecture, etc so your assumption that it is NOT 64 bit (or 16 for that matter) is arbitrary and possibly completely wrong. – Edward Strange Nov 24 '10 at 18:33
  • @PigBen - "But compilers do produce output for that code," is ultimately why I negged this particular answer. It encourages this terribly flawed and erroneous pov. – Edward Strange Nov 24 '10 at 18:35
  • 1
    @PigBen: Yes, compiler implementers are usually pretty nice about being backwards compatible when it comes to UB. In this particular case, the interviewer could've been looking for any one of a number of answers: 1. The answer given by the OP 2. Wanted the OP to recognize that it is UB. 3. Wanted to OP to state that the answer will change depending on the size of an int. In any case, a question that results in UB is a horrible one to ask at an interview. – Praetorian Nov 24 '10 at 18:36
  • 1
    Being practical here, the compiler output is relevant if only in that it suggests that the OP's answer has the highest probability of creating a good impression on the interviewer of any specific unqualified numeric answer (if we're generous enough to consider it implicit in cdhowie's use of GCC and lack of information to the contrary that he's probably on x86, which is so ubiquitous that an answer specific to that still has some value). It's still worse than recognising it as undefined behaviour, but an interviewer who understood the entire situation would probably let it pass. – Tony Delroy Nov 25 '10 at 00:38
8
Binary of 1  : 0000 0000 0000 0000 0000 0000 0000 00001

Replace occurrence of 0 with 1 as you are going to calculate binary of negative no

How to calculate binary of negative numbers

Binary of -1 : 1111 1111 1111 1111 1111 1111 1111 11111

Left shift 4 : 1111 1111 1111 1111 1111 1111 1111 0000

Hex Representation of of resultant Left shift 4 will be

1111 : F 

0000 : 0

so calculated output will be :

FFFFFFF0

Your answer is Right.

Nightfirecat
  • 11,432
  • 6
  • 35
  • 51
Vishwanath Dalvi
  • 35,388
  • 41
  • 123
  • 155
3

Left shifting a negative number is undefined for the general case but we have to understand why this undefined behavior (UB)? Keep in mind that Most Significant Bit (MSb) is the sign bit. If this bit is a 1 the number is negative. If it is a zero the number is positive. This is critical information is lost with the first left shift. For example

-32768<<4

is the same thing as

0x8000<<4

(assuming a 16 bit machine for simplicity)

The result is, of course, 0 which doesn't really make any sense and is therefore UB.

In the specific case of the interview question from the OP, there is only one specific value we are concerned with...not the general case. -1 (0xffffffff on a 32 bit machine) shifted left 4 times will yield 0xfffffff0 as the OP originally thought.

semaj
  • 1,555
  • 1
  • 12
  • 25
  • What you're describing is not undefined behavior, it's unspecified/implementation defined (depending on doc reqs). Furthermore, -1 is not always '1111...111'. It could be '1000...0001' or '111...1110'. I'm still not completely convinced that -1 << X is undefined (the first sentence in 5.8/2 would seem to allow it), but we still can't say what the result is going to be without knowing what kind of negative number representation is being used and how large the type is. – Edward Strange Nov 24 '10 at 20:29
  • 1
    If it is undefined, my guess as to reason is the possible involvement of overflow exceptions that's addition to the picture would mean the committee couldn't guarantee it to be even possible to let the program continue or how the OS would respond to such an event. THAT is undefined behavior. – Edward Strange Nov 24 '10 at 20:32
  • @Noah - I didn't realize -1 was represented by something other than '1111...111'. Just out of curiosity, what kind (examples ?) of implementation does not use '1111...111' to represent -1? – semaj Nov 24 '10 at 21:26
  • 1
    @semaj: The C standard allows implementations using 2's complement, 1's complement and sign-magnitude representations. – ninjalj Nov 24 '10 at 21:50
  • @semaj: further nit-pick / even for 2's complement, "if [MSB] is a zero the number is positive" should say "non-negative". Don't forget the number 0 has all bits 0 but is not positive. – Tony Delroy Nov 25 '10 at 00:49
  • It's impossible for the number to have all zero bits but not be positive. All zero bits is defined as zero for integer types. Furthermore, for unsigned values in the range of the corresponding signed type, the representations are identical, which is another reason zero must be zero. – R.. GitHub STOP HELPING ICE Dec 24 '10 at 22:23
1

It's undefined behavior.

$ 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
Konrad Borowski
  • 11,584
  • 3
  • 57
  • 71
-1

I ran this code on 3 different compilers and OS. All gave me this same answer as mentioned in the question. Until and unless someone came up with the compiler on which this is really undefined behavior, I will say the answer is RIGHT. If this is stable in 99.99% of the situations, then there are more chances of standard getting changed, than the compiler stop supporting it.

Manoj R
  • 3,197
  • 1
  • 21
  • 36
-4

I just wrote the code in a text file, compiled it, and YES, the answer is correct.

Erik Escobedo
  • 2,793
  • 24
  • 42
  • 4
    I usually upvote to counter anonymous downvotes, but in this case the answer is not only wrong but actively misguiding. Checking the behavior of a program compiled with a particular compiler and run on a particular system doesn't tell you what the standard requires (not to mention that the compiler can have a bug). Almost-exception: Comeau is a very conforming compiler that you can generally trust, and it's a great idea to test small code snippets with Comeau Online (free), but even Comeau has some bugs... – Cheers and hth. - Alf Nov 24 '10 at 18:15
  • 2
    @Akf: I understand. Thank you for your advice. It's been a long time since I worked with a compiled language and forgot all of this. I deserve the downvotes. Lesson learned u_u – Erik Escobedo Nov 24 '10 at 18:57
  • +1 for a good attitude anyway :-). Might as well delete the answer though...? Same point's exhaustingly covered by cdhowie, who for no more reason than having cut-and-pasted his code, got 3 votes! @Alf: useful insight re Comeau's to share - thanks (interesting counter-example here though - as you'd know, even Comeau compiles/test-runs on *some* particular CPU, so it's shift behaviour here is no more authoratative than any other compilers / this is a case where undefined behaviour can be expected to be allowed to fall through to the CPU level rather than a Standards-compliance issue). – Tony Delroy Nov 25 '10 at 00:56