87

In an interview I was confronted with a question such as this:

Your friend has given you a single source code file which prints the Fibonacci numbers on the console. Note that the main() block is empty and doesn't have any statements inside it.

Explain how this is possible (hint: global instance!)

I really want to know about this, how such a thing can be even possible!

Mafii
  • 7,227
  • 1
  • 35
  • 55
Hossein
  • 24,202
  • 35
  • 119
  • 224
  • 26
  • 14
    Because it's something that 1) I hadn't heard of, 2) is useful trivia because people ask it in interviews, 3) an interesting application of the language to know so that 4) I can recognize it and stab anyone in the face with a rusty shiv if I see them actually using it in production code. – OmnipotentEntity Jul 08 '13 at 15:43
  • 4
    A competent, professional C++ programmer will know the answer to this question. If the purpose of this *interview* question is to determine if the person being interviewed is a competent, professional C++ programmer, then the question shouldn't give them the answer. – John Dibling Jul 08 '13 at 15:47
  • 1
    In an interview setting, one alternative would be to have the logic inside any function in the code and log the output using `assert` or `#pragma message` etc. This will redirect the output to the console during compilation. The program may never even fully compile, but this sure is a fun way of getting to show your "out-of-the-box" thinking during the interview. This satisfies the quoted question as it does NOT mention anything about binary being generated; rather it just talks about a C file that can display "stuff" on the console. ;-) – TheCodeArtist Jul 10 '13 at 02:24
  • @OmnipotentEntity, actually knowing something will be run before or after the main is useful even in real product code. I'd like to show this SO question: http://stackoverflow.com/questions/2323458/how-to-ignore-false-positive-memory-leaks-from-crtdumpmemoryleaks – ZijingWu Jan 21 '14 at 08:07
  • 1
    Was it an interview for [IOCC](http://www.ioccc.org/)? :-) Ok, I admitt I do it often for initializing my factories or executing some test-code. Btw, '**single** source code file' is also a hint, that the entry-pint (main by default) is not replaced by linker. – Valentin H Jan 28 '15 at 20:55
  • 1
    @OmnipotentEntity I think it is to check if the person is aware of run-time loading procedure. The questions like "Pls. explain 4 types of memory in C and their initialization?" are boring. – Valentin H Jan 28 '15 at 21:02

6 Answers6

128

It is most likely implemented as (or a variant of it):

 void print_fibs() 
 {
       //implementation
 }

 int ignore = (print_fibs(), 0);

 int main() {}

In this code, the global variable ignore has to be initialized before entering into main() function. Now in order to initialize the global, print_fibs() needs to be executed where you can do anything — in this case, compute fibonacci numbers and print them! A similar thing I've shown in the following question (which I had asked long back):

Note that such code is not safe and should be best avoided in general. For example, the std::cout object may not be initialized when print_fibs() is executed, if so then what would std::cout do in the function? However, if in other circumstances, it doesn't depend on such initialization order, then it is safe to call initialization functions (which is a common practice in C and C++).

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • Not sure what you mean by *not safe*. It's a fairly common idiom to ensure initialization before entering `main` (for non-class types). – James Kanze Jul 08 '13 at 15:23
  • @JamesKanze: Is it guaranteed to initialize `std::cout` when `print_fibs()` is executed, for example? – Nawaz Jul 08 '13 at 15:24
  • @Nawaz In this case, yes. But you have a point in general: if you put `print_fibs` in a separate translation unit, and don't include `` in the translation unit in which it is invoked, you do run a risk. – James Kanze Jul 08 '13 at 15:26
  • 3
    @Nawaz It's probably worth citing the exact guarantees. Objects within a translation unit are guaranteed to be initialized in order. The standard stream objects are guaranteed to be initialized before or during the first initialization of an `std::ios_base::Init` object. And `` is guaranteed to behave "as if" it contained an instance of an `std::ios_base_Init` object at namespace scope. – James Kanze Jul 08 '13 at 15:30
  • @JamesKanze: The [other topic](http://stackoverflow.com/questions/4783404/is-main-really-start-of-a-c-program) discusses many things related to such code, which depends on the runtime initialization. – Nawaz Jul 08 '13 at 15:33
  • Possible silly mistake (maybe mine, of course) - what value does `print_fibs` return to the comma operator, given that the return type is `void`? I didn't think the C++ `void` type was a real type - though I sometimes wish there was a `voidvalue` or similar. –  Jul 08 '13 at 15:38
  • 3
    @Steve314: It doesn't return anything which is why I've used comma operator, to ensure that the type of the whole expression `(print_fibs(), 0)` is `int`. Here is [Online Demo](http://ideone.com/tBVB2l). – Nawaz Jul 08 '13 at 15:41
  • @Steve314: You can have a `void` value on the left side of a comma expression, since nothing tries to look at its value. – Joe Z Jul 08 '13 at 15:41
  • 1
    @Nawaz An alternative to the void function and the comma operator would be to return a `bool`, and the variable `bool fibsPrinted`. That's probably slightly cleaner _if_ the function only serves here. (But the difference is probably not enough to worry about.) – James Kanze Jul 08 '13 at 16:07
  • 1
    +1, Talk about awesome. Had to join stackoverflow just to upvote this question and this answer. – Fixed Point Jul 09 '13 at 01:58
  • @JamesKanze: The `std::cout` definition is not in `main.cpp` (only the declaration is in it)? That is,`std::cout` comes from different translation unit, while it is being used in a different translation unit, which is why I said it is not safe as `std::cout` is not guaranteed to be initialized before `print_fibs()` call. Does it make sense? or I missed something? – Nawaz Jul 09 '13 at 07:16
  • 1
    @Nawaz I'm not sure what your point is. The definition of `std::cout` is somewhere in the library. But as I have already pointed out, the standard _requires_ it to be initialized before the first constructor of an `std::ios_base::Init` object has finished, and it requires that including `` behave as if an `std::ios_base::Init` object were defined at namespace scope. If the translation unit includes `` before the definition of the object being initialized, `std::cout` is guaranteed to be constructed. – James Kanze Jul 09 '13 at 08:38
  • This is very cool, and it seems like it should work in C as well, but it doesn't. I get the error `error: initializer element is not constant`. Do you have any idea why? – gsgx Jul 22 '13 at 07:18
  • @gsingh2011: Unfortunately (or fortunately) we cannot do this in C , because C doesn't allow a variable with static storage duration to be intialized with non-const expression. Have a look at [this](http://stackoverflow.com/questions/3025050/error-initializer-element-is-not-constant-when-trying-to-initialize-variable-w) for details. – Nawaz Jul 22 '13 at 07:25
  • +1 for mention the std::cout initialize thing, which I have never think about. – ZijingWu Jan 21 '14 at 08:44
18

Hope this helps

class cls
{
  public:
    cls()
    {
      // Your code for fibonacci series
    }
} objCls;

int main()
{
}

So as soon as a global variable of the class is declared, the constructor is called and there you add the logic to print out the Fibonacci series.

Dr1Ku
  • 2,875
  • 3
  • 47
  • 56
Saksham
  • 9,037
  • 7
  • 45
  • 73
9

Yes it is possible. You need to declare a global instance of an object that calculates the Fibonacci numbers in the object constructor.

Mr. Beer
  • 255
  • 1
  • 5
4

I know some examples like that you tell. One way to get it is using the template metaprogramming. Using it you can move some compute process to the compilation.

Here you can get an example with the Fibonacci numbers

If you use it in a static class constructor and you can write the numbers without need to write any code in the main function.

Hope it helps you.

superarce
  • 403
  • 6
  • 14
3

Things can happen during initialization of global/static variables. The code will be trigger at the application start.

log0
  • 10,489
  • 4
  • 28
  • 62
3

All[*] constructors for file-scope objects get called before reaching main, as do all initializer expressions for non-object file-scope variables.

Edit: Also, all[*] destructors for all file-scope objects get called in reverse order of construction after main exits. You could, theoretically, put your fibonacci program in an object's destructor.

[*] Note that 'all' ignores the behavior of dynamically loading and unloading libraries that your program wasn't directly linked with. Those technically are outside the base C++ language, though.

Joe Z
  • 17,413
  • 3
  • 28
  • 39
  • _All_? Even those in dll's that are explicitly loaded after `main`? – James Kanze Jul 08 '13 at 15:24
  • Well, C++ doesn't technically define dynamically loaded libraries, so within pure C++, my statement is correct. So, shade it "All, save for initializers and file-scope objects contained in DLLs/DSOs loaded after reaching main." In this case, `main` is empty, so those DLLs/DSOs would have to be loaded by destructors, which is darn perverse. But, this being computer science, I suppose we should be careful with words like "all". – Joe Z Jul 08 '13 at 15:35
  • I added a caveat on 'all' to my answer above, and also added a note about dtors. – Joe Z Jul 08 '13 at 15:39
  • Yes, but hopefully that will come. Pre C++11 contained some weasel wording meant to allow DLLs, but which in practice only meant that technically, the guarantee wasn't always there, even though it was in all actual implementations, and much code depended on it. C++11 fixed that, at least. – James Kanze Jul 08 '13 at 16:09