/********************************************\
|????歡迎轉(zhuǎn)載, 但請(qǐng)保留作者姓名和原文鏈接, 祝您進(jìn)步并共勉!???? |
\********************************************/
C++對(duì)象模型(9) - 3.1 The Binding of a Data Member
作者: Jerry Cat
時(shí)間: 2006/11/15
鏈接:?
http://m.shnenglu.com/jerysun0818/archive/2006/11/15/15186.html
3.1 The Binding of a Data Member
Consider the following program fragment:.
// A third party foo.h header file
// pulled in from somewhere
extern float x;
// the programmer's Point3d.h file
class Point3d
{
public:
?? Point3d( float, float, float );
?? // question:? which x is returned and set?
?? float X() const { return x; }
?? void X( float new_x ) const { x = new_x; }
?? // ...
private:
?? float x, y, z;
};
If I were to ask which x the Point3d member X() returns—the class instance or the extern instance—everyone today would answer the class instance, and everyone would be right. Most everyone, however, would probably be surprised to learn that this answer was not always correct.
早期的C++將其解析為X()函數(shù)引用的是全局?jǐn)?shù)據(jù). 所以早期的C++程序員發(fā)明了倆防范寫法(至今還有人用):
(1). Placing all data members first in the class declaration to ensure the right binding:
class Point3d
{
?? // defensive programming style #1
?? // place all data first ...
?? float x, y, z;
public:
?? float X() const { return x; }
?? // ... etc. ...
};
(2). Placing all inline functions, regardless of their size, outside the class declaration:
class Point3d
{
public:
?? // defensive programming style #2
?? // place all inlines outside the class
?? Point3d();
?? float X() const;
?? void X( float ) const;
?? // ... etc. ...
};
inline float
Point3d::
X() const
{
?? return x;
}
// ... etc. ...
extern int x;
class Point3d
{
public:
?? ...
?? // analysis of function body delayed until
?? // closing brace of class declaration seen.
?? float X() const { return x; }
?? ...
private:
?? float x;
?? ...
};
// in effect, analysis is done here
the analysis of the member function's body is delayed until the entire class declaration is seen. Thus the binding of a data member within the body of an inline member function does not occur until after the entire class declaration is seen.
但是This is not true of the argument list of the member function, however. Names within the argument list are still resolved in place at the point they are first encountered. Nonintuitive bindings between extern and nested type names, therefore, can still occur. In the following code fragment, for example, the type of length in both member function signatures resolves to that of the global typedef—that is, to int. When the subsequent declaration of the nested typedef of length is encountered, the Standard requires that the earlier bindings be flagged as illegal:
typedef int length;
class Point3d
{
public:
?? // oops: length resolves to global
?? // ok: _val resolves to Point3d::_val
?? mumble( length val ) { _val = val; }
?? length mumble() { return _val; }
?? // ...
private:
?? // length must be seen before its first
?? // reference within the class.? This
?? // declaration makes the prior reference illegal.
?? typedef float length;
?? length _val;
?? // ...
};
This aspect of the language still requires the general defensive programming style of always placing nested type declarations at the beginning of the class. In our example, placing the nested typedef defining length above any of its uses within the class corrects the nonintuitive binding.(數(shù)據(jù)成員定義還是要放在最前面)
posted @
2006-11-15 17:04 Jerry Cat 閱讀(528) |
評(píng)論 (0) |
編輯 收藏
/********************************************\
|????歡迎轉(zhuǎn)載, 但請(qǐng)保留作者姓名和原文鏈接, 祝您進(jìn)步并共勉!???? |
\********************************************/
C++對(duì)象模型(8) -
Chapter 3. The Semantics of Data
?
作者: Jerry Cat
時(shí)間: 2006/11/15
鏈接:?
http://m.shnenglu.com/jerysun0818/archive/2006/11/15/15185.html
;-----------------------------------------------------------------------
;Chapter 3. The Semantics of Data
;-----------------------------------------------------------------------
Chapter 3. The Semantics of Data - 空類不空
class X {};
class Y : public virtual X {};
class Z : public virtual X {};
class A : public Y, public Z {};
None of these classes contains any explicit data—any anything, in fact, except an inheritance
relationship—so he apparently believed the size of each class should be 0. It wasn't,
of course—not even the apparently benign class X:
sizeof X yielded 1
sizeof Y yielded 8
sizeof Z yielded 8
sizeof A yielded 12
Let's look at each declaration in turn and see what's going on. An empty class, such as
// sizeof X == 1
class X {};
in practice is never empty. Rather it has an associated size of 1 byte—a char member inserted
by the compiler. This allows two objects of the class, such as
X a, b;
if ( &a == &b ) cerr << "yipes!" << endl;//to be allocated unique addresses in memory.哈!
// sizeof Y == sizeof Z == 8
class Y : public virtual X{};
class Z : public virtual X{};
On his machine, the size of both classes Y and Z is 8. This size, however, is partially machine dependent. It also depends in part on the compiler implementation being used. The given size of both class Y and class Z on any machine is the interplay of three factors:
(1). Language support overhead. There is an associated overhead incurred in the language support of virtual base classes. Within the derived class, this overhead is reflected as some form of pointer, either to the virtual base class subobject or to an associated table within which either the address or offset to the virtual base class subobject is stored. On my correspondent's machine, the pointer is 4 bytes. (Virtual base classes are discussed in Section 3.4.)
(2). Compiler optimization of recognized special cases. There is the 1 byte size of the virtual base class X subobject also present within Y (and Z). Traditionally, this is placed at the end of the "fixed" (that is, invariant) portion of the derived class. Some compilers now provide special support for an empty virtual base class (the paragraph following item 3 discusses this in more detail). Our correspondent's compiler, however, did not provide this special handling.
(3). Alignment constraints. The size of class Y (and Z) at this point is 5 bytes. On most machines, aggregate structures have an alignment constraint so that they can be efficiently loaded from and stored to memory. On my correspondent's machine, alignment of an aggregate is on a 4-byte boundary. So class Y (and Z) requires 3 bytes of padding. The result is a final size of 8.
The C++ object model representation for nonstatic data members optimizes for space and access time (and to preserve compatibility with the C language layout of the C struct) by storing the members directly within each class object. This is also true for the inherited nonstatic data members of both virtual and nonvirtual base classes, although the ordering of their layout is left undefined. Static data members are maintained within the global data segment of the program and do not affect the size of individual class objects.(靜態(tài)數(shù)據(jù)成員被放在全局?jǐn)?shù)據(jù)段, 并不影響單個(gè)類的大小)
?
Only one instance of a static data member of a class exists within a program regardless of the number of times that class is an object of direct or indirect derivation. (The static data members of a template class behave slightly differently. See Section 7.1 for a discussion.)模板類的靜態(tài)數(shù)據(jù)成語(yǔ)有所不同
類的大小讓你吃驚地"大"的原因來(lái)源于2方面:
(1). Additional data members added by the compilation system to support some language functionality (primarily the virtuals)
(2). Alignment requirements on the data members and data structures as a whole
posted @
2006-11-15 16:55 Jerry Cat 閱讀(592) |
評(píng)論 (0) |
編輯 收藏
從笑話中悟出C++開(kāi)發(fā)管理之"道"
1. 程序員寫出自認(rèn)為沒(méi)有Bug的代碼。
2. 軟件測(cè)試,發(fā)現(xiàn)了20個(gè)Bug。
3. 程序員修改了10個(gè)Bug,并告訴測(cè)試組另外10個(gè)不是Bug。
4. 測(cè)試組發(fā)現(xiàn)其中5個(gè)改動(dòng)根本無(wú)法工作,同時(shí)又發(fā)現(xiàn)了15個(gè)新Bug。
5. 重復(fù)3次步驟3和步驟4。
6. 鑒于市場(chǎng)方面的壓力,為了配合當(dāng)初制定的過(guò)分樂(lè)觀的發(fā)布時(shí)間表,產(chǎn)品終于上市了。
7. 用戶發(fā)現(xiàn)了137個(gè)新Bug。
8. 已經(jīng)領(lǐng)了項(xiàng)目獎(jiǎng)金的程序員不知跑到哪里去了。
9. 新組建的項(xiàng)目組修正了差不多全部137個(gè)Bug,但又發(fā)現(xiàn)了456個(gè)新Bug。
10. 最初那個(gè)程序員從斐濟(jì)給飽受拖欠工資之苦的測(cè)試組寄來(lái)了一張明信片。整個(gè)測(cè)試組集體辭職.
11. 公司被競(jìng)爭(zhēng)對(duì)手惡意收購(gòu)。收購(gòu)時(shí),軟件的最終版本包含783個(gè)Bug。
12. 新CEO走馬上任。公司雇了一名新程序員重寫該軟件。
13. 程序員寫出自認(rèn)為沒(méi)有Bug的代碼。
要我說(shuō),如果真有這樣的公司,不倒閉對(duì)不起人民。
這個(gè)笑話從程序員開(kāi)始,到程序員結(jié)束,從頭到尾都在說(shuō)程序員的不是。但是我要說(shuō)的是,這完全是管理者的失敗,從整個(gè)過(guò)程中,看不到任何管理工作。這種管理者不但無(wú)知無(wú)能,還很無(wú)恥——將自己的失敗責(zé)任推給程序員。
1、程序員憑什么證明他的代碼沒(méi)有BUG?有Test case嗎?有Code review嗎?這個(gè)環(huán)節(jié)管理缺失。
2、測(cè)試發(fā)現(xiàn)BUG有進(jìn)行BUG管理嗎?有跟蹤嗎?這個(gè)環(huán)節(jié)管理缺失。
3、憑什么證明程序員已經(jīng)把那10個(gè)BUG修改好了?另10個(gè)又為什么不是BUG?BUG的評(píng)價(jià)標(biāo)準(zhǔn)難道是程序員說(shuō)了算?這個(gè)環(huán)節(jié)管理缺失。
4、5個(gè)不能工作的BUG修改問(wèn)題有沒(méi)有追究責(zé)任?增加新BUG是修改過(guò)程中不可避免的事情,但是如果有有效的單元測(cè)試機(jī)制,可以大大減少這種情況。這個(gè)環(huán)節(jié)管理缺失。
5、迭代是正常的,但是問(wèn)題處理于發(fā)散而不是收斂發(fā)展,可見(jiàn)沒(méi)有有效的管理調(diào)控。這個(gè)環(huán)節(jié)管理缺失。
6、過(guò)于樂(lè)觀的時(shí)間表和不可能達(dá)到的最后期限,都表現(xiàn)出管理者的無(wú)知和無(wú)能。而在這樣的情況下強(qiáng)行推出產(chǎn)品,那就是無(wú)知者無(wú)畏了。
7、這是對(duì)用戶的不負(fù)責(zé)任,管理者要負(fù)最大的責(zé)任。
8、這樣的情況還能發(fā)項(xiàng)目獎(jiǎng)金,只能說(shuō)管理者不是一般的愚蠢。
9、管理工作沒(méi)有任何的改進(jìn),問(wèn)題仍然處于發(fā)散迭代狀態(tài)。管理工作依然沒(méi)有到位。
10、拖欠測(cè)試部門工資體現(xiàn)出管理者對(duì)質(zhì)量管理工作的忽視以及對(duì)人力資源管理方面一無(wú)所知。
11、送被收購(gòu)者兩個(gè)字:活該。送收購(gòu)者兩個(gè)字:瞎眼。
12、可見(jiàn)新管理者與原管理者半斤八兩,都沒(méi)有認(rèn)識(shí)到問(wèn)題的根本所在。不過(guò)也只有這樣的管理者才會(huì)作出收購(gòu)這種公司的決策。
13、歷史的重演是必然的。
一個(gè)正常的企業(yè)或是項(xiàng)目,其運(yùn)作必須應(yīng)該是循環(huán)向上進(jìn)行的。而保障這種運(yùn)行的工作就是管理。而管理工作的主要內(nèi)容就是控制,包括控制循環(huán)的節(jié)奏——不能太快也不能太慢,控制發(fā)展的方向——只能向上不能向下,控制運(yùn)作的穩(wěn)定——不能大起大落或時(shí)聚時(shí)散等。
而這一切,在這個(gè)例子中都看不到。
在這個(gè)笑話的例子中,一切都是以開(kāi)發(fā)工作在驅(qū)動(dòng),這首先就是一個(gè)方向性錯(cuò)誤,產(chǎn)品是為用戶服務(wù)的,當(dāng)然應(yīng)該是以用戶和市場(chǎng)作為驅(qū)動(dòng),并且結(jié)合自身的能力最終 確定工作的重點(diǎn)。這一錯(cuò)誤折射出管理者對(duì)被管理的內(nèi)容很不了解,只好任由比較了解的程序員擺布——事實(shí)上他們除了技術(shù),并不會(huì)了解更多。
一個(gè)管理者如果對(duì)自己所管理的內(nèi)容不了解,他就不可能管理得好。
這是一件毫無(wú)疑問(wèn)的事,可是國(guó)內(nèi)的軟件業(yè)似乎總是不相信這一點(diǎn)。中國(guó)軟件業(yè)中流毒最深的謊言之一就是:
管理者只要懂管理就可以,不需要懂技術(shù)。
其實(shí)這不過(guò)是那些無(wú)知無(wú)能無(wú)恥的管理者為了騙錢而編出來(lái)的,相信這句話的人必將付出金錢的代價(jià)。
其次是質(zhì)量管理。基本的質(zhì)量管理常識(shí)告訴我們,每次循環(huán)結(jié)束前,最重的工作就是總結(jié)改進(jìn)。只有這樣才能保證循環(huán)運(yùn)作是向上發(fā)展,而不是失去控制地向下發(fā)展。 也只有有效的質(zhì)量管理,才能保證迭代過(guò)程是收斂發(fā)展,并最終達(dá)到目標(biāo)。但在這個(gè)例子中,這個(gè)部分顯然是缺失的——其中雖然有測(cè)試部門,但是他們的作用僅僅 是質(zhì)量管理中的質(zhì)量檢測(cè)環(huán)節(jié),管理部分還是缺失的。
然后是人力資源管理。軟件開(kāi)發(fā)是一項(xiàng)勞動(dòng)密集型的工作,雖然這是腦力勞動(dòng),但同樣意味著人在因素在其中占有決定性的地位。而例子中未改完BUG的程 序員拿到項(xiàng)目獎(jiǎng)金,而同樣辛苦工作的測(cè)試人員卻被拖欠薪資,除了表現(xiàn)出管理者對(duì)他們的工作內(nèi)容的不了解,以及對(duì)質(zhì)量管理工作的不重視以外,還表現(xiàn)出管理者 完全不會(huì)管人,這是一種謀殺團(tuán)隊(duì)的行為——謀殺一個(gè)團(tuán)隊(duì)遠(yuǎn)比建設(shè)要容易得多。
最后,這個(gè)失敗的管理者把他的經(jīng)歷編成這個(gè)笑話,讓大家看到他被程序員們害得多慘,把程序員妖魔化為一群騙子。但只要稍懂管理的人簡(jiǎn)單分析一下就可以看出來(lái),只不過(guò)是這個(gè)人的無(wú)知和無(wú)能造成了他現(xiàn)在的結(jié)果,而把責(zé)任推給別人的行為更是表現(xiàn)出他的無(wú)恥。
作為身居高位的管理者,如果連應(yīng)該承擔(dān)的責(zé)任都要推卸,他們還能勝任什么事情呢?
posted @
2006-10-26 01:35 Jerry Cat 閱讀(931) |
評(píng)論 (3) |
編輯 收藏
函數(shù)指針的聲明和回調(diào)的實(shí)現(xiàn)
?? 程序員常常需要實(shí)現(xiàn)回調(diào)。本文將討論函數(shù)指針的基本原則并說(shuō)明如何使用函數(shù)指針實(shí)現(xiàn)回調(diào)。注意這里針對(duì)的是普通的函數(shù),不包括完全依賴于不同語(yǔ)法和語(yǔ)義規(guī)則的類成員函數(shù)(類成員指針將在另文中討論)。
聲明函數(shù)指針
?? 回調(diào)函數(shù)是一個(gè)程序員不能顯式調(diào)用的函數(shù);通過(guò)將回調(diào)函數(shù)的地址傳給調(diào)用者從而實(shí)現(xiàn)調(diào)用。要實(shí)現(xiàn)回調(diào),必須首先定義函數(shù)指針。盡管定義的語(yǔ)法有點(diǎn)不可思議,但如果你熟悉函數(shù)聲明的一般方法,便會(huì)發(fā)現(xiàn)函數(shù)指針的聲明與函數(shù)聲明非常類似。請(qǐng)看下面的例子:
void f();// 函數(shù)原型
上面的語(yǔ)句聲明了一個(gè)函數(shù),沒(méi)有輸入?yún)?shù)并返回void。那么函數(shù)指針的聲明方法如下:
void (*) ();
?? 讓我們來(lái)分析一下,左邊圓括弧中的星號(hào)是函數(shù)指針聲明的關(guān)鍵。另外兩個(gè)元素是函數(shù)的返回類型(void)和由邊圓括弧中的入口參數(shù)(本例中參數(shù)是空)。注意本例中還沒(méi)有創(chuàng)建指針變量-只是聲明了變量類型。目前可以用這個(gè)變量類型來(lái)創(chuàng)建類型定義名及用sizeof表達(dá)式獲得函數(shù)指針的大小:
// 獲得函數(shù)指針的大小
unsigned psize = sizeof (void (*) ());
// 為函數(shù)指針聲明類型定義
typedef void (*pfv) ();
pfv是一個(gè)函數(shù)指針,它指向的函數(shù)沒(méi)有輸入?yún)?shù),返回類行為void。使用這個(gè)類型定義名可以隱藏復(fù)雜的函數(shù)指針語(yǔ)法。
指針變量應(yīng)該有一個(gè)變量名:
void (*p) (); //p是指向某函數(shù)的指針
?? p是指向某函數(shù)的指針,該函數(shù)無(wú)輸入?yún)?shù),返回值的類型為void。左邊圓括弧里星號(hào)后的就是指針變量名。有了指針變量便可以賦值,值的內(nèi)容是署名匹配的函數(shù)名和返回類型。例如:
void func()
{
/* do something */
}
p = func;
p的賦值可以不同,但一定要是函數(shù)的地址,并且署名和返回類型相同。
傳遞回調(diào)函數(shù)的地址給調(diào)用者
?? 現(xiàn)在可以將p傳遞給另一個(gè)函數(shù)(調(diào)用者)- caller(),它將調(diào)用p指向的函數(shù),而此函數(shù)名是未知的:
void caller(void(*ptr)())
{
ptr(); /* 調(diào)用ptr指向的函數(shù) */
}
void func();
int main()
{
p = func;
caller(p); /* 傳遞函數(shù)地址到調(diào)用者 */
}
?? 如果賦了不同的值給p(不同函數(shù)地址),那么調(diào)用者將調(diào)用不同地址的函數(shù)。賦值可以發(fā)生在運(yùn)行時(shí),這樣使你能實(shí)現(xiàn)動(dòng)態(tài)綁定。
調(diào)用規(guī)范
?? 到目前為止,我們只討論了函數(shù)指針及回調(diào)而沒(méi)有去注意ANSI C/C++的編譯器規(guī)范。許多編譯器有幾種調(diào)用規(guī)范。如在Visual C++中,可以在函數(shù)類型前加_cdecl,_stdcall或者_(dá)pascal來(lái)表示其調(diào)用規(guī)范(默認(rèn)為_(kāi)cdecl)。C++ Builder也支持_fastcall調(diào)用規(guī)范。調(diào)用規(guī)范影響編譯器產(chǎn)生的給定函數(shù)名,參數(shù)傳遞的順序(從右到左或從左到右),堆棧清理責(zé)任(調(diào)用者或者被調(diào)用者)以及參數(shù)傳遞機(jī)制(堆棧,CPU寄存器等)。
?? 將調(diào)用規(guī)范看成是函數(shù)類型的一部分是很重要的;不能用不兼容的調(diào)用規(guī)范將地址賦值給函數(shù)指針。例如:
// 被調(diào)用函數(shù)是以int為參數(shù),以int為返回值
__stdcall int callee(int);
// 調(diào)用函數(shù)以函數(shù)指針為參數(shù)
void caller( __cdecl int(*ptr)(int));
// 在p中企圖存儲(chǔ)被調(diào)用函數(shù)地址的非法操作
__cdecl int(*p)(int) = callee; // 出錯(cuò)
?? 指針p和callee()的類型不兼容,因?yàn)樗鼈冇胁煌恼{(diào)用規(guī)范。因此不能將被調(diào)用者的地址賦值給指針p,盡管兩者有相同的返回值和參數(shù)列。
posted @
2006-10-24 20:37 Jerry Cat 閱讀(1255) |
評(píng)論 (1) |
編輯 收藏
mutable關(guān)鍵字
關(guān)鍵字mutable是C++中一個(gè)不常用的關(guān)鍵字,他只能用于類的非靜態(tài)和非常量數(shù)據(jù)成員
我們知道一個(gè)對(duì)象的狀態(tài)由該對(duì)象的非靜態(tài)數(shù)據(jù)成員決定,所以隨著數(shù)據(jù)成員的改變,
對(duì)像的狀態(tài)也會(huì)隨之發(fā)生變化!
如果一個(gè)類的成員函數(shù)被聲明為const類型,表示該函數(shù)不會(huì)改變對(duì)象的狀態(tài),也就是
該函數(shù)不會(huì)修改類的非靜態(tài)數(shù)據(jù)成員.但是有些時(shí)候需要在該類函數(shù)中對(duì)類的數(shù)據(jù)成員
進(jìn)行賦值.這個(gè)時(shí)候就需要用到mutable關(guān)鍵字了
例如:
class Demo
{
public:
??? Demo(){}
??? ~Demo(){}
public:
??? bool getFlag() const
??? {
??????? m_nAccess++;
??????? return m_bFlag;
??? }
private:
??? int? m_nAccess;
??? bool m_bFlag;
};
int main()
{
??? return 0;
}
編譯上面的代碼會(huì)出現(xiàn) error C2166: l-value specifies const object的錯(cuò)誤
說(shuō)明在const類型的函數(shù)中改變了類的非靜態(tài)數(shù)據(jù)成員.
這個(gè)時(shí)候需要使用mutable來(lái)修飾一下要在const成員函數(shù)中改變的非靜態(tài)數(shù)據(jù)成員
m_nAccess,代碼如下:
class Demo
{
public:
??? Demo(){}
??? ~Demo(){}
public:
??? bool getFlag() const
??? {
??????? m_nAccess++;
??????? return m_bFlag;
??? }
private:
??? mutable int? m_nAccess;
??? bool m_bFlag;
};
int main()
{
??? return 0;
}
這樣再重新編譯的時(shí)候就不會(huì)出現(xiàn)錯(cuò)誤了!
?
?
volatile關(guān)鍵字
volatile是c/c++中一個(gè)鮮為人知的關(guān)鍵字,該關(guān)鍵字告訴編譯器不要持有變量的臨時(shí)拷貝,它可以適用于基礎(chǔ)類型
如:int,char,long......也適用于C的結(jié)構(gòu)和C++的類。當(dāng)對(duì)結(jié)構(gòu)或者類對(duì)象使用volatile修飾的時(shí)候,結(jié)構(gòu)或者
類的所有成員都會(huì)被視為volatile.
使用volatile并不會(huì)否定對(duì)CRITICAL_SECTION,Mutex,Event等同步對(duì)象的需要
例如:
int i;
i = i + 3;
無(wú)論如何,總是會(huì)有一小段時(shí)間,i會(huì)被放在一個(gè)寄存器中,因?yàn)樗阈g(shù)運(yùn)算只能在寄存器中進(jìn)行。一般來(lái)說(shuō),volatitle
關(guān)鍵字適用于行與行之間,而不是放在行內(nèi)。
我們先來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的函數(shù),來(lái)觀察一下由編譯器產(chǎn)生出來(lái)的匯編代碼中的不足之處,并觀察volatile關(guān)鍵字如何修正
這個(gè)不足之處。在這個(gè)函數(shù)體內(nèi)存在一個(gè)busy loop(所謂busy loop也叫做busy waits,是一種高度浪費(fèi)CPU時(shí)間的循環(huán)方法)
void getKey(char* pch)
{
?while (*pch == 0)
??;
}
當(dāng)你在VC開(kāi)發(fā)環(huán)境中將最優(yōu)化選項(xiàng)都關(guān)閉之后,編譯這個(gè)程序,將獲得以下結(jié)果(匯編代碼)
;?????? while (*pch == 0)
$L27
?; Load the address stored in pch
?mov eax, DWORD PTR _pch$[ebp]
?; Load the character into the EAX register
?movsx eax, BYTE PTR [eax]
?; Compare the value to zero
?test eax, eax
?; If not zero, exit loop
?jne $L28
?;
?jmp $L27
$L28
;}
這段沒(méi)有優(yōu)化的代碼不斷的載入適當(dāng)?shù)牡刂罚d入地址中的內(nèi)容,測(cè)試結(jié)果。效率相當(dāng)?shù)牡停墙Y(jié)果非常準(zhǔn)確
現(xiàn)在我們?cè)賮?lái)看看將編譯器的所有最優(yōu)化選項(xiàng)開(kāi)關(guān)都打開(kāi)以后,重新編譯程序,生成的匯編代碼,和上面的代碼
比較一下有什么不同
;{
?; Load the address stored in pch
?mov eax, DWORD PTR _pch$[esp-4]
?; Load the character into the AL register
?movsx al, BYTE PTR [eax]
;?while (*pch == 0)
?; Compare the value in the AL register to zero
?test al, al
?; If still zero, try again
?je SHORT $L84
?;
;}
從代碼的長(zhǎng)度就可以看出來(lái),比沒(méi)有優(yōu)化的情況要短的多。需要注意的是編譯器把MOV指令放到了循環(huán)之外。這在
單線程中是一個(gè)非常好的優(yōu)化,但是,在多線程應(yīng)用程序中,如果另一個(gè)線程改變了變量的值,則循環(huán)永遠(yuǎn)不會(huì)
結(jié)束。被測(cè)試的值永遠(yuǎn)被放在寄存器中,所以該段代碼在多線程的情況下,存在一個(gè)巨大的BUG。解決方法是重新
寫一次getKey函數(shù),并把參數(shù)pch聲明為volatile,代碼如下:
void getKey(volatile char* pch)
{
?while (*pch == 0)
??;
}
這次的修改對(duì)于非最優(yōu)化的版本沒(méi)有任何影響,下面請(qǐng)看最優(yōu)化后的結(jié)果:
;{
?; Load the address stored in pch
?mov eax, DWORD PTR _pch$[esp-4]
;?????? while (*pch == 0)
$L84:
?; Directly compare the value to zero
?cmp BYTE PTR [eax], 0
?; If still zero, try again
?je SHORT $L84
?;
;}
這次的修改結(jié)果比較完美,地址不會(huì)改變,所以地址聲明被移動(dòng)到循環(huán)之外。地址內(nèi)容是volatile,所以每次循環(huán)
之中它不斷的被重新檢查。
把一個(gè)const volatile變量作為參數(shù)傳遞給函數(shù)是合法的。如此的聲明意味著函數(shù)不能改變變量的值,但是變量的
值卻可以被另一個(gè)線程在任何時(shí)間改變掉。
explicit關(guān)鍵字
我們?cè)诰帉憫?yīng)用程序的時(shí)候explicit關(guān)鍵字基本上是很少使用,它的作用是"禁止單參數(shù)構(gòu)造函數(shù)"被用于自動(dòng)型別轉(zhuǎn)換,
其中比較典型的例子就是容器類型,在這種類型的構(gòu)造函數(shù)中你可以將初始長(zhǎng)度作為參數(shù)傳遞給構(gòu)造函數(shù).
例如:
你可以聲明這樣一個(gè)構(gòu)造函數(shù)
class Array
{
public:
?explicit Array(int size);
?......
};
在這里explicit關(guān)鍵字起著至關(guān)重要的作用,如果沒(méi)有這個(gè)關(guān)鍵字的話,這個(gè)構(gòu)造函數(shù)有能力將int轉(zhuǎn)換成Array.一旦這種
情況發(fā)生,你可以給Array支派一個(gè)整數(shù)值而不會(huì)引起任何的問(wèn)題,比如:
Array arr;
...
arr = 40;
此時(shí),C++的自動(dòng)型別轉(zhuǎn)換會(huì)把40轉(zhuǎn)換成擁有40個(gè)元素的Array,并且指派給arr變量,這個(gè)結(jié)果根本就不是我們想要的結(jié)果.如果
我們將構(gòu)造函數(shù)聲明為explicit,上面的賦值操作就會(huì)導(dǎo)致編譯器報(bào)錯(cuò),使我們可以及時(shí)發(fā)現(xiàn)錯(cuò)誤.
需要注意的是:explicit同樣也能阻止"以賦值語(yǔ)法進(jìn)行帶有轉(zhuǎn)型操作的初始化";
例如:
Array arr(40);//正確
Array arr = 40;//錯(cuò)誤
看一下以下兩種操作:
X x;
Y y(x);//顯式類型轉(zhuǎn)換
另一種
X x;
Y y = x;//隱式類型轉(zhuǎn)換
這兩種操作存在一個(gè)小小的差別,第一種方式式通過(guò)顯式類型轉(zhuǎn)換,根據(jù)型別x產(chǎn)生了型別Y的新對(duì)象;第二種方式通過(guò)隱式轉(zhuǎn)換
產(chǎn)生了一個(gè)型別Y的新對(duì)象.
explicit關(guān)鍵字的應(yīng)用主要就是上面所說(shuō)的構(gòu)造函數(shù)定義種,參考該關(guān)鍵字的應(yīng)用可以看看STL源代碼,其中大量使用了該關(guān)鍵字
?
__based關(guān)鍵字
該關(guān)鍵字主要用來(lái)解決一些和共享內(nèi)存有關(guān)的問(wèn)題,它允許指針被定義為從某一點(diǎn)開(kāi)始算的32位偏移值,而不是內(nèi)存種的絕對(duì)位置
舉個(gè)例子:
typedef struct tagDEMOSTRUCT {
?int a;
?char sz[10];
} DEMOSTRUCT, * PDEMOSTRUCT;
HANDLE hFileMapping = CreateFileMapping(...);
LPVOID lpShare = (LPDWORD)MapViewOfFile(...);
DEMOSTRUCT __based(lpShare)* lpDemo;
上面的例子聲明了一個(gè)指針lpDemo,內(nèi)部?jī)?chǔ)存的是從lpShare開(kāi)始的偏移值,也就是lpHead是以lpShare為基準(zhǔn)的偏移值.
上面的例子種的DEMOSTRUCT只是隨便定義的一個(gè)結(jié)構(gòu),用來(lái)代表任意的結(jié)構(gòu).
雖然__based指針使用起來(lái)非常容易,但是,你必須在效率上付出一定的代價(jià).每當(dāng)你用__based指針處理數(shù)據(jù),CPU都必須
為它加上基地址,才能指向真正的位置.
在這里我只是介紹了幾個(gè)并不時(shí)很常見(jiàn)的關(guān)鍵字的意義即用法,其他那些常見(jiàn)的關(guān)鍵字介紹他們的文章已經(jīng)不少了在這里
就不再一一介紹了.希望這些內(nèi)容能對(duì)大家有一定的幫助!
posted @
2006-10-21 13:20 Jerry Cat 閱讀(2359) |
評(píng)論 (7) |
編輯 收藏
方興東抨擊博客實(shí)名制 稱此舉將摧毀中國(guó)博客
出處:TOM科技| 2006年10月20日 14:51 ? ?? ?? ? 現(xiàn)在還不清楚博客實(shí)名制的實(shí)際情況,所以簡(jiǎn)單評(píng)論還為時(shí)過(guò)早。但是,可以肯定的是,如果違背博客本質(zhì),違背全球互聯(lián)網(wǎng)基本規(guī)則,推進(jìn)不合理的實(shí)名制,那么,這項(xiàng)政策的直接后果就是對(duì)國(guó)內(nèi)博客服務(wù)造成明顯的FUD效應(yīng)(擔(dān)心、疑慮和懷疑),犯下中國(guó)互聯(lián)網(wǎng)有史以來(lái)最大的錯(cuò)誤!也是難以挽回的錯(cuò)誤。
博客用戶在失去基本安全感的情況下,首先選擇千百萬(wàn)家國(guó)外的博客網(wǎng)站。因?yàn)椋磥?lái)任何一個(gè)大型網(wǎng)站都將提供博客服務(wù)。除非中國(guó)全面封閉互聯(lián)網(wǎng),否則選擇國(guó)外的博客服務(wù)成為中國(guó)網(wǎng)民的必然。
這種不合理政策將直接摧毀中國(guó)新興的博客服務(wù)網(wǎng)站,成為國(guó)外博客網(wǎng)站市場(chǎng)推廣最好的方式。將造成中國(guó)博客全面向國(guó)外服務(wù)商遷移,失去一個(gè)產(chǎn)業(yè)的發(fā)展機(jī)會(huì)。目前,擁有千萬(wàn)級(jí)博客用戶的國(guó)外博客網(wǎng)站,已經(jīng)有10家左右。百萬(wàn)級(jí)用戶的國(guó)外博客網(wǎng)站在數(shù)十家之多。加上各大網(wǎng)站都已經(jīng)或者很快提供博客服務(wù)。國(guó)外博客網(wǎng)站將是中國(guó)實(shí)名制政策的最大贏家。變相為它們做最強(qiáng)有力的推廣。
因?yàn)橹袊?guó)不可能讓全世界的博客網(wǎng)站都接受中國(guó)特色的實(shí)名制,所以國(guó)內(nèi)博客網(wǎng)站將受到摧毀性的打擊(除非中國(guó)互聯(lián)網(wǎng)與世隔絕)。而更大的損失還不僅僅在于幾家博客網(wǎng)站本身。
中國(guó)的博客用戶如果全面遷移到國(guó)外博客網(wǎng)站,被迫流浪,那么,中國(guó)互聯(lián)網(wǎng)將成為一座空城,中國(guó)2.0應(yīng)用將失去真正用戶的家,那時(shí)候,不要說(shuō)控制,就是基本的管理和引導(dǎo)都無(wú)從談起。未來(lái)中國(guó)的網(wǎng)絡(luò)社會(huì)將失去自己的網(wǎng)絡(luò)國(guó)民。博客在國(guó)外安家落戶,要再遷移回來(lái)其難度就不可同日而語(yǔ),成本巨大!所以,今后連糾錯(cuò)的機(jī)會(huì)都很難!
所以,不符合博客發(fā)展的內(nèi)在規(guī)律,不與全世界互聯(lián)網(wǎng)發(fā)展接軌,而出臺(tái)不合理的實(shí)名制,損害的將不僅僅是博客行業(yè)和互聯(lián)網(wǎng)行業(yè),而是斷送中國(guó)整個(gè)社會(huì)和未來(lái)。
建設(shè)好中國(guó)互聯(lián)網(wǎng)和博客,很不容易,但是要?dú)У魠s很容易。所以,我始終堅(jiān)信,中國(guó)互聯(lián)網(wǎng)發(fā)展十年,成績(jī)輝煌。不可能會(huì)有人要苦心積慮把它摧毀掉,不可能讓發(fā)展開(kāi)倒車。所以,在這個(gè)簡(jiǎn)單的邏輯下,在實(shí)名制風(fēng)雨欲來(lái)的輿論中,我始終保持樂(lè)觀心態(tài):不合理的實(shí)名制不可能實(shí)行。
也就是說(shuō),這個(gè)問(wèn)題的本質(zhì)在于:誰(shuí)敢摧毀中國(guó)互聯(lián)網(wǎng)的發(fā)展?!其用意和出發(fā)點(diǎn)何在?!
(此文來(lái)自方興東的博客)
|
posted @
2006-10-20 19:00 Jerry Cat 閱讀(454) |
評(píng)論 (1) |
編輯 收藏
C++面試題集4
一. 華為一道面試題-1-n排序
有N個(gè)大小不等的自然數(shù)(1--N),請(qǐng)將它們由小到大排序。
要求程序算法:時(shí)間復(fù)雜度為O(n),空間復(fù)雜度為O(1)。
網(wǎng)上轉(zhuǎn)的,一開(kāi)始也沒(méi)有注意到最開(kāi)始的半句。
算法:N個(gè)不等的自然數(shù)1~N,排序完成后必然為1~N。所以可以一次遍歷,遇到a[i]!=i的就把a(bǔ)[i]和a[a[i]]交換。
void sort(int a[], int n)
{
?int i;
?int t; /*臨時(shí)變量:空間復(fù)雜度O(1)*/
?for (i=1; i<n+1; i++) /*時(shí)間復(fù)雜度O(n)*/
?{
?while(a[i]!=i)
? {
?t = a[a[i]];
?a[a[i]] = a[i];//排好一個(gè)元素
?a[i] = t;
? }
?}
}
二. 一次遍歷 找 鏈表倒數(shù)第n個(gè)節(jié)點(diǎn)
?一道面試題目,阿明和晨晨看到并且告訴我答案的。要求通過(guò)一次遍歷找到鏈表中倒數(shù)第n個(gè)節(jié)點(diǎn),鏈表可能相當(dāng)大,可使用輔助空間,但是輔助空間的數(shù)目必須固定,不能和n有關(guān)。
算法思想:兩根指針,第一根先出發(fā),相距n步后第二根出發(fā)。然后同時(shí)步進(jìn),直到第一根指針達(dá)到末尾。
struct iNode {
int value;
iNode * next;
};
iNode * getresult(iNode * head,int n)
{
iNode *pfirst;
iNode *psecond;
pfirst=head;
int counter;
for(counter=0;counter<n;counter++) {
?pfirst=pfirst->next;
}
psecond=head;
while(pfirst!=NULL) {
?pfirst=pfirst->next;
?psecond=psecond->next;
}
return psecond;
}
三. VC++學(xué)習(xí)筆記
1.?????? 日期轉(zhuǎn)成字符串:
?? COleDateTime??? ww;
ww=COleDateTime::GetCurrentTime();
AfxMessageBox(ww.Format("%Y-%m-%d %H:%M:%S"));
2.?????? 字符串轉(zhuǎn)成日期:
COleDateTime dt;
?????? dt.ParseDateTime(“2006-08-08 08:08:08”);
3.?????? 資源文件
資源文件名:xxx.rc,其中要包含的主要文件:resource.h和afxres.h
4.?????? vc開(kāi)發(fā)環(huán)境沒(méi)有自動(dòng)提示時(shí):
?? 刪除 目錄下的ncb文件 ,再打開(kāi)一般就ok了
5.?????? 利用_variant_t 取數(shù)據(jù)庫(kù)數(shù)據(jù)的方法:
?? _variant_t ibb;
?????? ibb=(_variant_t)rs->GetCollect("inta");
?????? if(ibb.vt!=VT_NULL)
?????? {
????????????? m_b=ibb.lVal;
?????? }
6.?????? 平時(shí)取記錄集字段值的方法:
?? (LPCTSTR)(_bstr_t)rs->GetCollect("datea")
7.?????? DoModal()可以返回兩個(gè)結(jié)果 IDOK,IDCANCEL,他們都是int型,分別是:1,2。通過(guò)EndDialog(IDOK)的方式返回。
8.?????? 一般將數(shù)據(jù)庫(kù)連接方面的信息放到app中。則AfxGetApp()非常重要,如;
?? CAdo2App* mapp=(CAdo2App*)AfxGetApp();
?? Map->conn->Execute(sql,NULL,adCmdText);
9.?????? DECLARE_DYNCREATE(類名),IMPLEMENT_DYNCREATE(類名,基類名)? 使得由CObject繼承來(lái)的類在程序運(yùn)行的時(shí)候能夠動(dòng)態(tài)的創(chuàng)建。
10.?? DECLARE_DYNAMIC(類名),IMPLEMENT_DYNAMIC(類名,基類名)? 可以在運(yùn)行時(shí)獲得該類的信息
11.?? DECLARE_SERIAL(類名),IMPLEMENT_SERIAL(類名,基類名,0)為一個(gè)可以串行化的CObject派生類產(chǎn)生必要的C++標(biāo)題代碼
12.?? 獲得文檔的方法: CMainFrame * pFrame=(CMainFrame *) AfxGetMainWnd();
CPClientDoc * pDoc =(CPClientDoc *) pFrame->GetActiveDocument();
?
13.?? 獲得視圖的方法:CMainFrame * pFrame=(CMainFrame *) AfxGetMainWnd();
myView =(CPClientView*) pFrame->GetActiveView();
14.?? 如果要引用全局變量或者全局方法,須在當(dāng)前類中引入:extern 名字;
posted @
2006-10-19 21:11 Jerry Cat 閱讀(3924) |
評(píng)論 (10) |
編輯 收藏
摘要: 上一篇中我介紹了一種通過(guò)封閉Critical Section對(duì)象而方便的使用互斥鎖的方式,文中所有的例子是兩個(gè)線程對(duì)同一數(shù)據(jù)一讀一寫,因此需要讓它們?cè)谶@里互斥,不能同時(shí)訪問(wèn)。而在實(shí)際情況中可能會(huì)有更復(fù)雜的情況出現(xiàn),就是多個(gè)線程訪問(wèn)同一數(shù)據(jù),一部分是讀,一部分是寫。我們知道只有讀-寫或?qū)?寫同時(shí)進(jìn)行時(shí)可能會(huì)出現(xiàn)問(wèn)題,而讀-讀則可以同時(shí)進(jìn)行,因?yàn)樗鼈儾粫?huì)對(duì)數(shù)據(jù)進(jìn)行修改,所以也有必要在C++中封裝一種方...
閱讀全文
posted @
2006-10-19 14:35 Jerry Cat 閱讀(1514) |
評(píng)論 (1) |
編輯 收藏
摘要: 線程同步是多線程程序設(shè)計(jì)的核心內(nèi)容,它的目的是正確處理多線程并發(fā)時(shí)的各種問(wèn)題,例如線程的等待、多個(gè)線程訪問(wèn)同一數(shù)據(jù)時(shí)的互斥,防死鎖等。Win32提供多種內(nèi)核對(duì)象和手段用于線程同步,如互斥量、信號(hào)量、事件、臨界區(qū)等。所不同的是,互斥量、信號(hào)量、事件都是Windows的內(nèi)核對(duì)象,當(dāng)程序?qū)@些對(duì)象進(jìn)行控制時(shí)會(huì)自動(dòng)轉(zhuǎn)換到核心態(tài),而臨界區(qū)本身不是內(nèi)核對(duì)象,它是工作在用戶態(tài)的。我們知道從用戶態(tài)轉(zhuǎn)換到核心態(tài)是需...
閱讀全文
posted @
2006-10-19 14:33 Jerry Cat 閱讀(1536) |
評(píng)論 (1) |
編輯 收藏
int Strcmp(char *str1, char *str2)
{
?? int i=0;
?? int b=0;
?? while(str1[i]||str2[i])
?? {
????? if(str1[i]>str2[i])
????? {
???????? b=1;break;
????? }
????? else if(str1[i]<str2[i])
????? {
???????? b=-1;break;
????? }
????? i++;
?? }
?? return b;
}
***************************************************************************************************************
1.說(shuō)出下面這個(gè)程序的運(yùn)行結(jié)果,并簡(jiǎn)要敘述其理由:
char buf1[10]="hello";
char buf2[10]="hello";
if (buf1==buf2)
printf("equal!");
else printf("not equal!");
因?yàn)閎uf1,buf2分配了不同的內(nèi)存塊,而比較的是數(shù)組名,實(shí)際上是兩個(gè)分別指向數(shù)組起始元素地址的指針。
2.指出下面這段程序中存在一些什么問(wèn)題:
int loop,a[5];
int* p=a;
for (loop=0;loop<5;loop++)
{ p++;
*p=loop;
}
數(shù)組a[5]在創(chuàng)建時(shí)沒(méi)有初始化, 在for循環(huán)里也沒(méi)有起到完全初始化數(shù)組的作用,而且對(duì)一塊未知內(nèi)存賦值。在最后一輪循環(huán)
結(jié)束時(shí)p指向了數(shù)組a[5]的最后一個(gè)元素的下一個(gè)地址。
string 系列
char * strcpy( char *strDest, const char *strSrc )
{
assert( (strDest != NULL) && (strSrc != NULL) );
char *address = strDest;
while( (*strDest++ = * strSrc++) != ‘\0’ );
return address;
}
char* strncpy(char* strdest, const char* strsrc, int n)
{
?? assert((strdest != NULL) && (strsrc != NULL));
?? char* address = strdest;
?? while(n-- > 0)
????? *strdest++ = *strsrc++;
?? return address;
}
int strcmp(const char* str1, const char* str2)
{
?? assert((str1 != NULL) && (str2 != NULL);
?? int ret = 0;
?? while (!(ret = (unsigned char*)*str1 - (unsigned char*)*str2) && (*str2))
?? {
????? str1++;
????? str2++;
?? }
?? if (ret > 0)
????? ret = 1;
?? else if (ret < 0)
????? ret = -1;
?? return ret;
}
int strlen(const char* str)
{
?? assert(str != NULL);
?? int len = 0;
?? while ('\0' != *str++)
????? len++;
?? return len;
}
類string的構(gòu)造函數(shù)
string::string(const char* str)
{
?? if(str == NULL)
?? {
????? m_data = new char[1];
????? *m_data = '\0';
??? }
??? else
??? {
?????? int length = strlen(str);
?????? m_data = new char[str + 1];
?????? strcpy(m_data, str);
???? }
}
string 的析構(gòu)函數(shù)
string::~string()
{
?? delete [] m_data;
}
string 的拷貝構(gòu)造函數(shù)
string ::string(const string& other)
{
?? int len = strlen(other.m_data);
?? m_data = new char[len + 1];
?? strcpy(m_data, other.m_data);
}
string 的賦值函數(shù)
string& string::operator=(const string& other)
{
?? if (this == &other)
????? return *this;
?? delete [] m_data;
?? int len = strlen(other.m_data);
?? m_data = new char[len + 1];
?? strcpy(m_data, other.m_data);
?? return *this;
}??
不用任何局部和全局變量實(shí)現(xiàn)int strlen(char *a)
int strlen(char *a) {
??? if('\0' == *a)
??????? return 0;
??? else
??????? return 1 + strlen(a + 1);
}
1)sizeof相關(guān)系列問(wèn)題
2)const相關(guān)系列問(wèn)題
3)大量林銳書的習(xí)題,以及各種變種
這三個(gè)幾乎是每次必出現(xiàn)
下面的這些是程序相關(guān)題,很多都是以前有討論過(guò)的,還請(qǐng)各位大俠能整理個(gè)比較適合做面試時(shí)答案的解答,多謝了.最好能給出
討論鏈接,讓我等后輩有學(xué)習(xí)的機(jī)會(huì).
1)求出相似度的算法.
2)寫出二分查找的代碼.
int binary_search(int* arr, int key, int n)
{
?? int low = 0;
?? int high = n - 1;
?? int mid;
?? while (low <= high)
?? {
????? mid = (high + low) / 2;
????? if (arr[mid] > k)
???????? high = mid - 1;
????? else if (arr[mid] < k)
???????? low = mid + 1;
????? else
???????? return mid;
?? }
?? return -1;
}
??
3)寫出在母串中查找子串出現(xiàn)次數(shù)的代碼.
*4)寫出快速排序或者某種排序算法代碼
出現(xiàn)次數(shù)相當(dāng)頻繁
5)寫出查找從一個(gè)集合中輸出所有子集合的算法.
*6)實(shí)現(xiàn)strcpy函數(shù)
char* strcpy(char* dest, const char* src)
{
?? assert((dest != NULL) && (src != NULL));
?? char* address = dest;
?? while ('\0' != (*dest++ = *src++));
?? return address;
}
出現(xiàn)次數(shù)相當(dāng)頻繁
*7)實(shí)現(xiàn)strcmp函數(shù)
int mystrcmp(const char* str1, const char* str2)
{
?? assert((str1 != NULL) && (str2 != NULL));
?? int ret = 0;
?? while (!(ret = *(unsigned char*)str1 - *(unsigned char*)str2) && *str2)
?? {
????? str1++;
????? str2++;
?? }
?? if (ret > 0)
????? ret = 1;
?? else if (ret < 0)
????? ret = -1;
?? return ret;
}
??
出現(xiàn)次數(shù)相當(dāng)頻繁
8)將一個(gè)單鏈表逆序
struct test
{
?? int number;
?? double score;
?? test* next;
}
void reverse(test*& head)
{
?? test* pe = head;
?? test* ps = head->next;
?? while(ps != NULL)
?? {
????? pe->next = ps->next;
????? ps->next = head;
????? head = ps;
????? ps = pe->next;
??? }
}?
??
?????
?????
9)循環(huán)鏈表的節(jié)點(diǎn)對(duì)換和刪除。
*10)將一個(gè)數(shù)字字符串轉(zhuǎn)換為數(shù)字."1234" -->1234
#i nclude<iostream>
using namespace std;
int f(char* s)
{
?? int k = 0;
?? while (*s)
?? {
????? k = 10 * k + (*s++)- '0';
?????
?? }
?? return k;
}
int main()
{
?? int digit = f("4567");
?? cout<<digit<<endl;
?? cin.get();
}
出現(xiàn)次數(shù)相當(dāng)頻繁
11)實(shí)現(xiàn)任意長(zhǎng)度的整數(shù)相加或者相乘功能。
*12)寫函數(shù)完成內(nèi)存的拷貝
一個(gè)內(nèi)存拷貝函數(shù)的實(shí)現(xiàn)體
void *memcpy(void *pvTo,const void *pvFrom,size_t size)
{
assert((pvTo!=NULL)&&(pvFrom!=NULL));
byte *pbTo=(byte*)pvTo; //防止地址被改變
byte *pbFrom=(byte*)pvFrom;
while (size-- >0)
*pbTo++ = *pbForm++;
return pvTo;
}
出現(xiàn)次數(shù)相當(dāng)頻繁
?
.筆試:
1)寫一個(gè)內(nèi)存拷貝函數(shù),不用任何庫(kù)函數(shù).就是前些時(shí)候本版討論的那個(gè)問(wèn)題.
?void* memcpy(void* pvTo, const void* pvFrom, size_t size)
?{
??? assert((pvTo != NULL) && (pvFrom != NULL));
??? byte* pbTo = pvTo;
??? byte* pbFrom = pbFrom;
??? while (size-- > 0)
??? {
?????? *pbTo++ = *pbFrom++;
??? }
??? return pvTo;
?}
2)將一個(gè)單鏈表逆序.(這個(gè)問(wèn)題是個(gè)常規(guī)的數(shù)據(jù)結(jié)構(gòu)問(wèn)題.不過(guò)不小心時(shí)會(huì)損失效率)
3)客房預(yù)定的問(wèn)題.根據(jù)客戶報(bào)的人數(shù),客房等級(jí)來(lái)從預(yù)備的客房中選擇出所有符合要求的
客房號(hào).客戶沒(méi)有要求等級(jí)時(shí),只考慮人數(shù)因素就可以了.要考慮有些客房已經(jīng)預(yù)定的情況.
(寫代碼是要考慮好彼此的效率)
4)對(duì)于一個(gè)無(wú)序序列進(jìn)行二分查找
線排序再查找
5)將一個(gè)數(shù)字字符串轉(zhuǎn)換為數(shù)字."1234" -->1234
int convert(char* str)
{
?? int k = 0;
?? while (*str != '\0')
?? {
????? k = k * 10 + *s++ - '0';
?? }
?? return k;
}
6)在文件(調(diào)用庫(kù)函數(shù)創(chuàng)建的,不用考慮數(shù)據(jù)庫(kù)的方式)中讀入信息(包括職工號(hào),職工產(chǎn)量)
.根據(jù)輸入的信息(包括職工號(hào),職工產(chǎn)量)..檢測(cè)是否有相同的職工號(hào)記錄,如有,則增加其
產(chǎn)量.如沒(méi)有,則創(chuàng)建新的記錄.最后的記錄排序的依據(jù)是職工產(chǎn)量(降序),如果產(chǎn)量相同,則
按職工號(hào)(升序). (具體的題目記不太清了,這個(gè)題目有點(diǎn)長(zhǎng).哪位也去筆試了.請(qǐng)修正一下
子)
.
2.面試
1)找出兩個(gè)中文句子的相似度.(例如"中國(guó)江蘇南京" "江蘇省中國(guó)南京市".實(shí)際上是指的
同一個(gè)地方.面試官的要求是一分鐘給出求相似度的算法.)(幸好聽(tīng)老師講過(guò)中文分詞,要不
然當(dāng)場(chǎng)就掛了)
2)寫出二分查找的代碼.
3)將上述代碼通用化.(在 C 的規(guī)范內(nèi).就是我前面所的那個(gè)問(wèn)題)
4)寫出在母串中查找子串出現(xiàn)次數(shù)的代碼.(不顧及效率時(shí)好說(shuō).當(dāng)時(shí)一不留神把 KMP 說(shuō)了
出來(lái),結(jié)果又讓我描述整個(gè)過(guò)程.汗..只好從頭又學(xué)了.不過(guò)沒(méi)有冷場(chǎng),邊學(xué)邊說(shuō).hoho)
5)如何看待在函數(shù)中定義很多靜態(tài)變量.
6)寫出quick_sort
7)寫出查找從一個(gè)集合中輸出所有子集合的算法.
8)有關(guān)于各種類型指針.各種數(shù)據(jù)類型的 sizeof 運(yùn)算結(jié)果( 在 C 中)
posted @
2006-10-18 23:15 Jerry Cat 閱讀(2505) |
評(píng)論 (1) |
編輯 收藏