打印編譯時間
#include <stdio.h>
int main()
{
printf("本程序的編譯時間爲:%s %s\n",__DATE__,__TIME__);
// printf("%d\n",__LINE__);
return 0;
}
主函數main爲空的情況下輸出helloworld
/*********/
void main()
{
}
/*********/
//以上的main函數不能修改,/***/可隨意添加代碼,至少4中方法
第一種:
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout<<"Hello World"<<endl;
}
};
A a;
void main()
{
}
第二種:
#include <iostream>
using namespace std;
#define main() main(){cout<<"Hello World"<<endl;} void test()
void main()
{
}
第三種:
#include <iostream>
using namespace std;
int print();
int a=print();
int print()
{
cout<<"Hello World"<<endl;
return 0;
}
void main()
{
}
第四種:利用VC6修改主函數的入口
#include <stdio.h>
#pragma comment(linker,"/entry:fun")
#pragma comment(lib,"msvcrt.lib")
int fun()
{
printf("hello world\n");
return 0;
}
void main()
{
;
}
暫時只有這四種了。。。。。註明一下,第四種還可以這樣玩. = =
#include <stdio.h>
#pragma comment(linker,"/entry:fun")
#pragma comment(lib,"msvcrt.lib")
void main();
int fun()
{
printf("hello world\n");
main();
printf("hello world\n");
return 0;
}
void main()
{
printf("main start\n");
}
這樣就實現用其他函數去調動去main函數了……只是玩一下而已的東西,,,說了這麼多,實際上是想表達main不是真正的程序的入口。在main之前有一些函數已經執行了,它們幫你分配堆棧,初始化寄存器。在main之後也有一些函數執行了,他們幫你做收尾工作。。。
好吧,抽象的話都是沒人鳥的。上一個Demo吧 - -!
#include <stdio.h>
void main()//VC下會崩潰!!VS不會
{
int x = 0;
scanf("%f",&x);
}
這個代碼應該能看懂吧,但是你故意用浮點數格式去進行輸入。那麼命運只有一個就是崩潰,上圖….
、
但是如果你這樣
#include <stdio.h>
void main()
{
float a = 1.0;
int x = 0;
scanf("%f",&x);
}
看到了吧,能夠成功執行,並且沒有崩潰。
那麼爲什麼呢???
加入了一個看似沒什麼影響的float a = 1.0;對編譯器產生了什麼樣的影響?
= =!一般來說吧,當編譯器見到了有float a = 1.0;這樣子明顯用過浮點數的痕跡,就會主動在main函數之前初始化浮點寄存器。這是第一點。然後還有一點,這是一條規則,凡是使用沒有初始化的浮點寄存器,那麼進程就只有崩潰的命運。
就是這兩條,構成了程序崩潰的條件,呃,要說明一點,在VS下,已經成功修復了這個BUG。現在已經不管什麼用了沒有浮點數的痕跡,一上來就初始化浮點數寄存器了。。
說了這麼多,只說了一點,main之前有函數執行,main函數之後也有函數執行。。。。
再給一個玩具代碼,可以跳過n個函數
#include <iostream>
using namespace std;
void Show()
{
cout<<"hello world"<<endl;
}
void fun()
{
void *p = NULL;
p = &p+2;
*(int*)p += 5;
}
void main()
{
Show();
fun();//執行一個fun函數讓跳過後面的Show函數
Show();
Show();
Show();
}
這個用到了越界訪問函數返回地址的原理。給出函數棧幀上的內存分佈