开发者

Why does this do whatever it does?

开发者 https://www.devze.com 2023-04-10 15:04 出处:网络
#incl开发者_如何学Cude <stdio.h> void littledot(){}//must use C, not C++ int main() { littledot(568,76,105,84,116,76,101,68,111,84);
#incl开发者_如何学Cude <stdio.h>
void littledot(){}//must use C, not C++

int main() {
   littledot(568,76,105,84,116,76,101,68,111,84);
   printf("%c%c%c%c%c%c%c%c%c\n");

   getchar();
   return 0;
}

The above code yields the result "LiTtLeDoT". Why does it do that? Why is 568 crucial?


This differs per platform and is UB (the implementation can do anything it wants*), but probably the arguments to littledot() are still on the stack after littledot() returns and printf prints those arguments from the stack.

NEVER RELY ON THIS!


*really anything. Afaik an ancient version of GCC started a videogame when it encountered something that would behave in an undefined way.


You were lucky. This is undefined behaviour, specifically the call to printf. The program could do anything. Your implementation happens to write "LiTtLeDoT".

The really is the nature of undefined behaviour. The compiler can do anything it wants. If you really want to know why it does what it does then you will need to look at the emitted object code. Looking at the C code will yield nothing because of the aforementioned undefined behaviour.


This is what's working reliably for me with Open Watcom 1.9 on Windows:

//must use C, not C++
#include <stdio.h>
#include <stdlib.h>

void
__stdcall // callee cleans up
littledot()
{
}

int main(void)
{
   littledot(/*568,*/'L','i','T','t','L','e','D','o','T');
   printf("%c%c%c%c%c%c%c%c%c\n");
   getchar();
   exit(0);
   return 0;
}

littledot() is called with a number of parameters that are passed on the stack.
If the calling convention for littledot() is __stdcall (or __fastcall), it will have to remove its parameters from the stack.
If it's __cdecl, then main() will have to remove them, but this won't work for us.

However, littledot() doesn't and can't do anything about the parameters because they're not specified, which is something you can do in C, but not C++.

So, what happens is that not only littledot()'s parameters remain on the stack after the call to it, but also the stack pointer is not restored (because neither littledot() nor main() remove the parameters, which is typically done by adjusting the stack pointer) and the stack pointer points to 'L'. Then there's the call to printf() that first places on the stack the address of the format string "%c%c%c%c%c%c%c%c%c\n" thus forming all expected parameters for the function on the stack. printf() happily prints the text and returns.

After that the stack isn't correctly balanced and doing return in main() is risky as the app may crash. Returning by means of exit(0) fixes that.

As all others have said, none of this is guaranteed to work. It may only work with specific compilers for specific OSes and then only sometimes.


http://codepad.org/tfRLaCB5

I'm sorry, what you claim the program to print is not what happens on my box and not what happens on codepad's box.

And the reason is, the program has undefined behavior. printf expects one additional argument (an int) for every %c you have in the format string. You don't give it those arguments, hence anything can happen.

You are in a situation where with certain implementations of printf, compiler options, certain compilers and certain ABIs, you end up with that output. But you should not think that this output is required by any specification.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号