Microsoftios
下面哪些調用轉換支持可變長度參數:c++
A. cdecl B. stdcall C. pascal D. fastcall數組
幾種函數調用方式:多線程
__cdecl 是C Declaration的縮寫,表示C語言默認的函數調用方法:全部參數從右到左依次入棧,這些參數由調用者清除,稱爲手動清棧。被調用函數不會要求調用者傳遞多少參數,調用者傳遞過多或者過少的參數,甚至徹底不一樣的參數都不會產生編譯階段的錯誤。併發
_stdcall 是StandardCall的縮寫,是C++的標準調用方式:全部參數從右到左依次入棧,若是是調用類成員的話,最後一個入棧的是this指針。這些堆棧中的參數由被調用的函數在返回後清除,稱爲自動清棧。函數在編譯的時候就必須肯定參數個數,而且調用者必須嚴格的控制參數的生成,不能多,不能少,不然返回後會出錯。函數
PASCAL 是Pascal語言的函數調用方式,也能夠在C/C++中使用,參數壓棧順序與前二者相反。返回時的清棧方式與_stdcall相同。this
_fastcall是編譯器指定的快速調用方式。因爲大多數的函數參數個數不多,使用堆棧傳遞比較費時。所以_fastcall一般規定將前兩個(或若干個)參數由寄存器傳遞,其他參數仍是經過堆棧傳遞。不一樣編譯器編譯的程序規定的寄存器不一樣。返回方式和_stdcall至關。spa
_thiscall 是爲了解決類成員調用中this指針傳遞而規定的。_thiscall要求把this指針放在特定寄存器中,該寄存器由編譯器決定。VC使用ecx,Borland的C++編譯器使用eax。返回方式和_stdcall至關。操作系統
_fastcall 和 _thiscall涉及的寄存器由編譯器決定,所以不能用做跨編譯器的接口。因此Windows上的COM對象接口都定義爲_stdcall調用方式。線程
C中不加說明默認函數爲_cdecl方式(C中也只能用這種方式),C++也同樣,可是默認的調用方式能夠在IDE環境中設置。
帶有可變參數的函數必須且只能使用_cdecl方式,例以下面的函數:
int printf(char * fmtStr, ...);
int scanf(char * fmtStr, ...);
如下代碼的輸出結果:
class A
{
public:
virtual void f()
{
cout<<"A:f()"<<endl;
}
void f() const
{
cout<<"A:f()const"<<endl;
}
};
class B:public A
{
public:
void f()
{
cout<<"B:f()"<<endl;
}
void f() const
{
cout<<"B:f()const"<<endl;
}
};
void ga(const A *a)
{
a->f();
}
int _tmain(intargc, _TCHAR* argv[])
{
A *a=new B();
a->f();
ga(a);
}
答案:B::f()A::f()const
第一個,b->f()爲動態綁定,輸出B::f沒問題
第二個,因爲函數ga的參數有const,因此調用成員函數也是調用const版本,可是const版本的不是虛函數,不存在動態綁定,因此輸出A::f const。
const 修飾函數和沒有const是不一樣的重載,對於非const對象調用非const函數,固然也能夠調用const函數(優先前者);然而對於const對象則只能調用const函數;其次,A中的f ()函數標註爲 virtual,那麼子類 B 中跟它原模原樣聲明即便沒有標註爲 virtual的函數依然是 virtual 函數。(c++規定,當一個成員函數被聲明爲虛函數後,其派生類中的同名函數都自動成爲虛函數。)
const是函數類型的一部分。虛函數重載的時候這個const也必須一致。若是基類的虛函數帶有const,而在子類的實現中沒有帶const,則至關於在子類中從新定義了一個新的函數。
定義虛函數的限制:
(1)非類的成員函數不能定義爲虛函數,類的成員函數中靜態成員函數和構造函數也不能定義爲虛函數,但能夠將析構函數定義爲虛函數。構造函數不能是虛函數,內聯函數也不能是虛函數。構造函數不能是虛函數緣由在於:首先構造函數構造一個對象時必須知道對象的實際類型,其次,虛函數的執行依賴於虛函數表,而虛函數表在構造函數中進行初始化工做。
(2)只須要在聲明函數的類體中使用關鍵字「virtual」將函數聲明爲虛函數,而定義函數時不須要使用關鍵字「virtual」。
(3)當將基類中的某一成員函數聲明爲虛函數後,派生類中的同名函數自動成爲虛函數。
(4)若是聲明瞭某個成員函數爲虛函數,則在該類中不能出現和這個成員函數同名而且返回值、參數個數、類型都相同的非虛函數。在以該類爲基類的派生類中,也不能出現這種同名函數。
子類中能夠不重寫父類中的虛函數:
class A
{
public:
virtual void f()
{
cout<<"A:f()"<<endl;
}
};
class B:public A
{
public:
void f2()
{
cout<<"B:f()"<<endl;
}
};
int main(){
A *a=new B();
a->f();
}
輸出結果:A:f()
但若是基類中定義的是純虛函數,而在子類中沒有實習,那麼在這個子類中,該函數仍然是純虛函數,且該子類也不能被實例化。
線程與進程
程序與進程的關係:程序是計算機指令的集合,它以文件的形式存儲在磁盤上,而進程一般被定義爲一個正在運行的程序的實例,是一個程序在其自身的地址空間中的一次執行活動。一個程序能夠對應多個進程,同時,在一個進程中也能夠同時訪問多個程序。
進程是資源申請、調度和獨立運行的單位,所以它使用系統中的運行資源。程序不能申請系統資源,不能被系統調度,也不能做爲獨立運行的單位,所以它不佔用系統的運行資源。
進程與線程的關係:
1)進程歷來不執行任何東西,它只是線程的容器。若要使進程完成某項操做,它必須擁有一個在它的環境中運行的線程,此線程負責執行包含在進程的地址空間中的代碼。也就是說,進程其實是線程的執行環境。
2)單個進程可能包含若干個線程,這些線程都「同時」(時間片)執行進程地址空間中的代碼。每一個進程至少擁有一個線程。當建立一個進程時,操做系統會自動建立這個進程的第一個線程,稱爲主線程,也就是執行主函數的線程。此後主線程能夠建立其餘線程。
3)進程和線程的主要差異在於它們是不一樣的操做系統資源管理方式。進程有獨立的地址空間,一個進程崩潰後,在保護模式下不會對其它進程產生影響,子進程和父進程有不一樣的代碼和數據空間。而線程只是一個進程中的不一樣執行路徑。線程有本身的堆棧和局部變量,但線程之間沒有單獨的地址空間,多個線程則共享數據空間,一個線程死掉就等於整個進程死掉,因此多進程的程序要比多線程的程序健壯。
4)在進程切換時,耗費資源較大,效率要差一些。但對於一些要求同時進行而且又要共享某些變量的併發操做,只能用線程,不能用進程。
如下代碼的輸出結果
int x=10;
x= x++;
printf("%d /n", x);
不一樣編譯器編譯出的結果不一樣。可能爲10(DevC++),也可能爲11(VC6.0).
如下const用法正確的是:
A. const int a; // a 是常數
B. int const a; // a 是常數
C. int const *a; // a 指向常數的指針
D. const int *a; // a 是常指針
E. int const *a; // a 是常指針
答案:A B C
注:D 和 E都是指向常量的指針,而 int * const a; 纔是常量指針。約束指針仍是約束常量主要看*的位置。
代碼驗證:
const int a=10;
int const b=11;
cout<<a<<" "<<b<<endl;
輸出:10 11
爲何下面的例子在使用一個const變量來初始化數組,ANSI C的編譯器會報告一個錯誤呢?
const int n = 5;
int a[n];
答案與分析:
1)這個問題討論的是「常量」與「只讀變量」的區別。常量,例如5, "abc",等,確定是只讀的,由於常量是被編譯器放在內存中的只讀區域,固然也就不可以去修改它。而「只讀變量」則是在內存中開闢一個地方來存放它的值,只不過這個值由編譯器限定不容許被修改。C語言關鍵字const就是用來限定一個變量不容許被改變的修飾符(Qualifier)。上述代碼中變量n被修飾爲只讀變量,惋惜再怎麼修飾也不是常量。而ANSI C規定數組定義時長度必須是「常量」,「只讀變量」也是不能夠的,「常量」不等於「不可變的變量」。
2)可是在標準C++中,這樣定義的是一個常量,這種寫法是對的。實際上,根據編譯過程及內存分配來看,這種用法原本就應該是合理的,只是ANSI C對數組的規定限制了它(實際上用GCC或VS2005編譯以上代碼,確實沒有錯誤產生,也沒有給出警告)。
3)那麼,在ANSI C中用什麼來定義常量呢?答案是enum類型和#define宏,這兩個均可以用來定義常量。
例:下面的代碼編譯器會報一個錯誤,請問,哪個語句是錯誤的呢?
typedef char * pStr;
char string[4] = "abc";
const char *p1 = string; //1式
const pStr p2 = string; //2式
p1++;
p2++;
答案與分析:
問題出在p2++上。
1)const使用的基本形式: const type m;
限定m不可變。
2)替換基本形式中的m爲1式中的*p1,替換後const char *p1;
限定*p1不可變,固然p1是可變的,所以問題中p1++是對的。
3)替換基本形式中的type爲2式中的pStr,替換後const pStr m;
限定m不可變,題中的pStr就是一種新類型,所以問題中p2不可變,p2++是錯誤的。
下面分別用const限定不可變的內容是什麼?
1)const在前面
const int nValue; //nValue是const
const char *pContent; //*pContent是const, pContent可變
const char* const pContent; //pContent和*pContent都是const
2)const在後面,與上面的聲明對等
int const nValue; //nValue是const
char const * pContent; //*pContent是const, pContent可變
char* const pContent; //pContent是const,*pContent可變
char const* const pContent; //pContent和*pContent都是const
答案與分析:
const和指針一塊兒使用是C語言中一個很常見的困惑之處,在實際開發中,特別是在看別人代碼的時候,經常會由於這樣而很差判斷做者的意圖,下面講一下個人判斷原則:
const只修飾其後的變量,至於const放在類型前仍是類型後並無區別。如:const int a和int const a都是修飾a爲const。*不是一種類型,若是*pType以前是某類型,那麼pType是指向該類型的指針
一個簡單的判斷方法:指針運算符*,是從右到左,那麼如:char const * pContent,能夠理解爲char const (* pContent),即* pContent爲const,而pContent則是可變的。
int const * p1,p2;
p2是const;(*p1)是一總體,所以(*p1)是const,但p1是可變的。int * p1,p2只表明p1是指向整型的指針,要表示p1、p2都是指針是需寫成int * p1,* p2。因此不管是* const p1,p2仍是const * p1,p2,裏面的*都是屬於p1的。
int const * const p1,p2;
p2是const,是前一個const修飾的,*p1也被前一個const修飾,而p1被後一個const修飾。
int * const p1,p2;
p1是const,(* const p1)是總體,因此const不修飾p2。
const在*的左邊,則指針指向的變量的值不可變;在*的右邊,則指針的指向不可變。簡記爲「左定值,右定向」。
1)指針指向的變量的值不能變,指向可變
int x = 1;
int y = 2;
const int* px = &x;
int const* px = &x; //這兩句表達式同樣效果
px = &y; //正確,容許改變指向
*px = 3; //錯誤,不容許改變指針指向的變量的值
2)指針指向的變量的值能夠改變,指向不可變
int x = 1;
int y = 2;
int* const px = &x;
px = &y; //錯誤,不容許改變指針指向
*px = 3; //正確,容許改變指針指向的變量的值
3)指針指向的變量的值不可變,指向不可變
int x = 1;
int y = 2;
const int* const px = &x;
int const* const px = &x;
px = &y; //錯誤,不容許改變指針指向
*px = 3; //錯誤,不容許改變指針指向的變量的值
附:
在c中,對於const定義的指針,不賦初值編譯不報錯,
即int* const px;等不會報錯。
可是,在C++中
int* const px;和const int* const px;會報錯,const int* px;不報錯。
必須初始化指針的指向int* const px = &x;const int* const px=&x;
強烈建議在初始化時說明指針的指向,防止出現野指針
有1000瓶水,其中有一瓶有毒,小白鼠只要嘗一點帶毒的水24小時後就會死亡至少要多少隻小白鼠才能在24小時鑑別出哪瓶水有毒。
給1000個瓶分別標上以下標籤(10位長度):
0000000001 (第1瓶)
0000000010 (第2瓶)
0000000011 (第3瓶)
......
1111101000 (第1000瓶)
從編號最後1位是1的全部的瓶子裏面取出1滴混在一塊兒(好比從第一瓶,第三瓶,…裏分別取出一滴混在一塊兒)並標上記號爲1。以此類推,從編號第一位是1的全部的瓶子裏面取出1滴混在一塊兒並標上記號爲10。如今獲得有10個編號的混合液,小白鼠排排站,分別標上10,9,…1號,並分別給它們灌上對應號碼的混合液。24小時過去了,過來驗屍:
從左到右,死了的小白鼠貼上標籤1,沒死的貼上0,最後獲得一個序號,把這個序號換成10進制的數字,就是有毒的那瓶水的編號。
3*4的格子有幾個矩形:
M*N網格中有橫豎各M+1、N+1條直線,其中,任意各取兩條均可以組成一個長方形。
C(4,2)*C(5,2)=6*10=60;
A(N,N)=N!
A(N,M)=N*(N-1)*…*(N-M+1)
C(N,M)=A(N,M)/A(M,M)
一條線把平面分紅兩塊,兩條線把平面分紅四塊,若是任意兩條線不平行,且沒有3條線交在同一點,問100條線將平面分紅多少塊。
答案:5051
1條直線最多將平面分紅2個部分;2條直線最多將平面分紅4個部分;3條直線最多將平面分紅7個部分;如今添上第4條直線.它與前面的3條直線最多有3個交點,這3個交點將第4條直線分紅4段,其中每一段將原來所在平面部分一分爲二,因此4條直線最多將平面分紅7+4=11個部分.
徹底相似地,5條直線最多將平面分紅11+5=16個部分;6條直線最多將平面分紅16+6=22個部分;7條直線最多將平面分紅22+7=29個部分;8條直線最多將平面分紅29+8=37個部分.
通常地,n條直線最多將平面分紅2+2+3....+N=(N*N+N+2)/2
有N個球,其中只有一個是重量較輕的,用天平只稱三次就能找到較輕的球,如下的N值哪一個是可能的?
A 12
B 16
C 20
D 24
E 28
3 個一次能夠測出來,3*3 = 9個之內 2 次,3*3*3 = 27個之內,3次!
下列代碼的輸出是什麼?
#include <iostream>
using namespace std;
class A{
public:
long a;
};
class B : public A
{
public:
long b;
};
void seta(A* data, int idx)
{
data[idx].a = 2; // 形參爲A的指針。數組步長按A的大小來取。
}
int main(int argc, char *argv[])
{
B data[4];
for(int i=0; i<4; ++i){
data[i].a = 1;
data[i].b = 1;
seta(data, i);
}
cout<<sizeof(A)<<endl; // 4
cout<<sizeof(B)<<endl; // 8
for(int i=0; i<4; ++i){
std::cout << data[i].a << data[i].b;
}
}
輸出爲22221111
附:
struct Test{
short int a;
short int b;
};
int main(int argc, char *argv[])
{
int test = 0x12345678;
printf("%x %x", (*(struct Test*)&test).a, (*(struct Test*)&test).b); // 5678 1234
}
//Intel是小端處理器