• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            asm, c, c++ are my all
            -- Core In Computer
            posts - 139,  comments - 123,  trackbacks - 0

            /********************************************\
            |????歡迎轉載, 但請保留作者姓名和原文鏈接, 祝您進步并共勉!???? |
            \********************************************/


            C++對象模型(9) - 3.1 The Binding of a Data Member

            作者: Jerry Cat
            時間: 2006/11/15
            鏈接:?
            http://www.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()函數引用的是全局數據. 所以早期的C++程序員發明了倆防范寫法(至今還有人用):
            (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.(數據成員定義還是要放在最前面)

            posted @ 2006-11-15 17:04 Jerry Cat 閱讀(480) | 評論 (0)編輯 收藏

            /********************************************\
            |????歡迎轉載, 但請保留作者姓名和原文鏈接, 祝您進步并共勉!???? |
            \********************************************/


            C++對象模型(8) - Chapter 3. The Semantics of Data
            ?

            作者: Jerry Cat
            時間: 2006/11/15
            鏈接:?
            http://www.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.(靜態數據成員被放在全局數據段, 并不影響單個類的大小)
            ?
            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.)模板類的靜態數據成語有所不同

            類的大小讓你吃驚地"大"的原因來源于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 閱讀(545) | 評論 (0)編輯 收藏

            從笑話中悟出C++開發管理之"道"

            1. 程序員寫出自認為沒有Bug的代碼。

            2. 軟件測試,發現了20個Bug。

            3. 程序員修改了10個Bug,并告訴測試組另外10個不是Bug。

            4. 測試組發現其中5個改動根本無法工作,同時又發現了15個新Bug。

            5. 重復3次步驟3和步驟4。

            6. 鑒于市場方面的壓力,為了配合當初制定的過分樂觀的發布時間表,產品終于上市了。

            7. 用戶發現了137個新Bug。

            8. 已經領了項目獎金的程序員不知跑到哪里去了。

            9. 新組建的項目組修正了差不多全部137個Bug,但又發現了456個新Bug。

            10. 最初那個程序員從斐濟給飽受拖欠工資之苦的測試組寄來了一張明信片。整個測試組集體辭職.

            11. 公司被競爭對手惡意收購。收購時,軟件的最終版本包含783個Bug。

            12. 新CEO走馬上任。公司雇了一名新程序員重寫該軟件。

            13. 程序員寫出自認為沒有Bug的代碼。

              要我說,如果真有這樣的公司,不倒閉對不起人民。

             這個笑話從程序員開始,到程序員結束,從頭到尾都在說程序員的不是。但是我要說的是,這完全是管理者的失敗,從整個過程中,看不到任何管理工作。這種管理者不但無知無能,還很無恥——將自己的失敗責任推給程序員。

             1、程序員憑什么證明他的代碼沒有BUG?有Test case嗎?有Code review嗎?這個環節管理缺失。

             2、測試發現BUG有進行BUG管理嗎?有跟蹤嗎?這個環節管理缺失。
             3、憑什么證明程序員已經把那10個BUG修改好了?另10個又為什么不是BUG?BUG的評價標準難道是程序員說了算?這個環節管理缺失。

             4、5個不能工作的BUG修改問題有沒有追究責任?增加新BUG是修改過程中不可避免的事情,但是如果有有效的單元測試機制,可以大大減少這種情況。這個環節管理缺失。

             5、迭代是正常的,但是問題處理于發散而不是收斂發展,可見沒有有效的管理調控。這個環節管理缺失。

             6、過于樂觀的時間表和不可能達到的最后期限,都表現出管理者的無知和無能。而在這樣的情況下強行推出產品,那就是無知者無畏了。

             7、這是對用戶的不負責任,管理者要負最大的責任。

             8、這樣的情況還能發項目獎金,只能說管理者不是一般的愚蠢。

             9、管理工作沒有任何的改進,問題仍然處于發散迭代狀態。管理工作依然沒有到位。

             10、拖欠測試部門工資體現出管理者對質量管理工作的忽視以及對人力資源管理方面一無所知。

             11、送被收購者兩個字:活該。送收購者兩個字:瞎眼。

             12、可見新管理者與原管理者半斤八兩,都沒有認識到問題的根本所在。不過也只有這樣的管理者才會作出收購這種公司的決策。

             13、歷史的重演是必然的。

             一個正常的企業或是項目,其運作必須應該是循環向上進行的。而保障這種運行的工作就是管理。而管理工作的主要內容就是控制,包括控制循環的節奏——不能太快也不能太慢,控制發展的方向——只能向上不能向下,控制運作的穩定——不能大起大落或時聚時散等。
             而這一切,在這個例子中都看不到。

             在這個笑話的例子中,一切都是以開發工作在驅動,這首先就是一個方向性錯誤,產品是為用戶服務的,當然應該是以用戶和市場作為驅動,并且結合自身的能力最終 確定工作的重點。這一錯誤折射出管理者對被管理的內容很不了解,只好任由比較了解的程序員擺布——事實上他們除了技術,并不會了解更多。

             一個管理者如果對自己所管理的內容不了解,他就不可能管理得好。

             這是一件毫無疑問的事,可是國內的軟件業似乎總是不相信這一點。中國軟件業中流毒最深的謊言之一就是:

             管理者只要懂管理就可以,不需要懂技術。

            其實這不過是那些無知無能無恥的管理者為了騙錢而編出來的,相信這句話的人必將付出金錢的代價。

             其次是質量管理?;镜馁|量管理常識告訴我們,每次循環結束前,最重的工作就是總結改進。只有這樣才能保證循環運作是向上發展,而不是失去控制地向下發展。 也只有有效的質量管理,才能保證迭代過程是收斂發展,并最終達到目標。但在這個例子中,這個部分顯然是缺失的——其中雖然有測試部門,但是他們的作用僅僅 是質量管理中的質量檢測環節,管理部分還是缺失的。

             然后是人力資源管理。軟件開發是一項勞動密集型的工作,雖然這是腦力勞動,但同樣意味著人在因素在其中占有決定性的地位。而例子中未改完BUG的程 序員拿到項目獎金,而同樣辛苦工作的測試人員卻被拖欠薪資,除了表現出管理者對他們的工作內容的不了解,以及對質量管理工作的不重視以外,還表現出管理者 完全不會管人,這是一種謀殺團隊的行為——謀殺一個團隊遠比建設要容易得多。

             最后,這個失敗的管理者把他的經歷編成這個笑話,讓大家看到他被程序員們害得多慘,把程序員妖魔化為一群騙子。但只要稍懂管理的人簡單分析一下就可以看出來,只不過是這個人的無知和無能造成了他現在的結果,而把責任推給別人的行為更是表現出他的無恥。

             作為身居高位的管理者,如果連應該承擔的責任都要推卸,他們還能勝任什么事情呢?

            posted @ 2006-10-26 01:35 Jerry Cat 閱讀(912) | 評論 (3)編輯 收藏

            函數指針的聲明和回調的實現

            ?? 程序員常常需要實現回調。本文將討論函數指針的基本原則并說明如何使用函數指針實現回調。注意這里針對的是普通的函數,不包括完全依賴于不同語法和語義規則的類成員函數(類成員指針將在另文中討論)。

            聲明函數指針

            ?? 回調函數是一個程序員不能顯式調用的函數;通過將回調函數的地址傳給調用者從而實現調用。要實現回調,必須首先定義函數指針。盡管定義的語法有點不可思議,但如果你熟悉函數聲明的一般方法,便會發現函數指針的聲明與函數聲明非常類似。請看下面的例子:

            void f();// 函數原型

            上面的語句聲明了一個函數,沒有輸入參數并返回void。那么函數指針的聲明方法如下:

            void (*) ();

            ?? 讓我們來分析一下,左邊圓括弧中的星號是函數指針聲明的關鍵。另外兩個元素是函數的返回類型(void)和由邊圓括弧中的入口參數(本例中參數是空)。注意本例中還沒有創建指針變量-只是聲明了變量類型。目前可以用這個變量類型來創建類型定義名及用sizeof表達式獲得函數指針的大小:

            // 獲得函數指針的大小
            unsigned psize = sizeof (void (*) ());

            // 為函數指針聲明類型定義
            typedef void (*pfv) ();

            pfv是一個函數指針,它指向的函數沒有輸入參數,返回類行為void。使用這個類型定義名可以隱藏復雜的函數指針語法。

            指針變量應該有一個變量名:

            void (*p) (); //p是指向某函數的指針

            ?? p是指向某函數的指針,該函數無輸入參數,返回值的類型為void。左邊圓括弧里星號后的就是指針變量名。有了指針變量便可以賦值,值的內容是署名匹配的函數名和返回類型。例如:

            void func()
            {
            /* do something */
            }
            p = func;

            p的賦值可以不同,但一定要是函數的地址,并且署名和返回類型相同。

            傳遞回調函數的地址給調用者

            ?? 現在可以將p傳遞給另一個函數(調用者)- caller(),它將調用p指向的函數,而此函數名是未知的:

            void caller(void(*ptr)())
            {
            ptr(); /* 調用ptr指向的函數 */
            }
            void func();
            int main()
            {
            p = func;
            caller(p); /* 傳遞函數地址到調用者 */
            }

            ?? 如果賦了不同的值給p(不同函數地址),那么調用者將調用不同地址的函數。賦值可以發生在運行時,這樣使你能實現動態綁定。

            調用規范

            ?? 到目前為止,我們只討論了函數指針及回調而沒有去注意ANSI C/C++的編譯器規范。許多編譯器有幾種調用規范。如在Visual C++中,可以在函數類型前加_cdecl,_stdcall或者_pascal來表示其調用規范(默認為_cdecl)。C++ Builder也支持_fastcall調用規范。調用規范影響編譯器產生的給定函數名,參數傳遞的順序(從右到左或從左到右),堆棧清理責任(調用者或者被調用者)以及參數傳遞機制(堆棧,CPU寄存器等)。

            ?? 將調用規范看成是函數類型的一部分是很重要的;不能用不兼容的調用規范將地址賦值給函數指針。例如:

            // 被調用函數是以int為參數,以int為返回值
            __stdcall int callee(int);

            // 調用函數以函數指針為參數
            void caller( __cdecl int(*ptr)(int));

            // 在p中企圖存儲被調用函數地址的非法操作
            __cdecl int(*p)(int) = callee; // 出錯


            ?? 指針p和callee()的類型不兼容,因為它們有不同的調用規范。因此不能將被調用者的地址賦值給指針p,盡管兩者有相同的返回值和參數列。

            posted @ 2006-10-24 20:37 Jerry Cat 閱讀(1219) | 評論 (1)編輯 收藏
            mutable關鍵字

            關鍵字mutable是C++中一個不常用的關鍵字,他只能用于類的非靜態和非常量數據成員
            我們知道一個對象的狀態由該對象的非靜態數據成員決定,所以隨著數據成員的改變,
            對像的狀態也會隨之發生變化!

            如果一個類的成員函數被聲明為const類型,表示該函數不會改變對象的狀態,也就是
            該函數不會修改類的非靜態數據成員.但是有些時候需要在該類函數中對類的數據成員
            進行賦值.這個時候就需要用到mutable關鍵字了

            例如:
            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;
            }

            編譯上面的代碼會出現 error C2166: l-value specifies const object的錯誤
            說明在const類型的函數中改變了類的非靜態數據成員.

            這個時候需要使用mutable來修飾一下要在const成員函數中改變的非靜態數據成員
            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;
            }

            這樣再重新編譯的時候就不會出現錯誤了!

            ?

            ?

            volatile關鍵字

            volatile是c/c++中一個鮮為人知的關鍵字,該關鍵字告訴編譯器不要持有變量的臨時拷貝,它可以適用于基礎類型
            如:int,char,long......也適用于C的結構和C++的類。當對結構或者類對象使用volatile修飾的時候,結構或者
            類的所有成員都會被視為volatile.

            使用volatile并不會否定對CRITICAL_SECTION,Mutex,Event等同步對象的需要
            例如:
            int i;
            i = i + 3;
            無論如何,總是會有一小段時間,i會被放在一個寄存器中,因為算術運算只能在寄存器中進行。一般來說,volatitle
            關鍵字適用于行與行之間,而不是放在行內。

            我們先來實現一個簡單的函數,來觀察一下由編譯器產生出來的匯編代碼中的不足之處,并觀察volatile關鍵字如何修正
            這個不足之處。在這個函數體內存在一個busy loop(所謂busy loop也叫做busy waits,是一種高度浪費CPU時間的循環方法)

            void getKey(char* pch)
            {
            ?while (*pch == 0)
            ??;
            }

            當你在VC開發環境中將最優化選項都關閉之后,編譯這個程序,將獲得以下結果(匯編代碼)
            ;?????? 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
            ;}

            這段沒有優化的代碼不斷的載入適當的地址,載入地址中的內容,測試結果。效率相當的低,但是結果非常準確

            現在我們再來看看將編譯器的所有最優化選項開關都打開以后,重新編譯程序,生成的匯編代碼,和上面的代碼
            比較一下有什么不同
            ;{
            ?; 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
            ?;
            ;}

            從代碼的長度就可以看出來,比沒有優化的情況要短的多。需要注意的是編譯器把MOV指令放到了循環之外。這在
            單線程中是一個非常好的優化,但是,在多線程應用程序中,如果另一個線程改變了變量的值,則循環永遠不會
            結束。被測試的值永遠被放在寄存器中,所以該段代碼在多線程的情況下,存在一個巨大的BUG。解決方法是重新
            寫一次getKey函數,并把參數pch聲明為volatile,代碼如下:

            void getKey(volatile char* pch)
            {
            ?while (*pch == 0)
            ??;
            }

            這次的修改對于非最優化的版本沒有任何影響,下面請看最優化后的結果:

            ;{
            ?; 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
            ?;
            ;}

            這次的修改結果比較完美,地址不會改變,所以地址聲明被移動到循環之外。地址內容是volatile,所以每次循環
            之中它不斷的被重新檢查。

            把一個const volatile變量作為參數傳遞給函數是合法的。如此的聲明意味著函數不能改變變量的值,但是變量的
            值卻可以被另一個線程在任何時間改變掉。


            explicit關鍵字


            我們在編寫應用程序的時候explicit關鍵字基本上是很少使用,它的作用是"禁止單參數構造函數"被用于自動型別轉換,
            其中比較典型的例子就是容器類型,在這種類型的構造函數中你可以將初始長度作為參數傳遞給構造函數.
            例如:
            你可以聲明這樣一個構造函數
            class Array
            {
            public:
            ?explicit Array(int size);
            ?......
            };
            在這里explicit關鍵字起著至關重要的作用,如果沒有這個關鍵字的話,這個構造函數有能力將int轉換成Array.一旦這種
            情況發生,你可以給Array支派一個整數值而不會引起任何的問題,比如:
            Array arr;
            ...
            arr = 40;
            此時,C++的自動型別轉換會把40轉換成擁有40個元素的Array,并且指派給arr變量,這個結果根本就不是我們想要的結果.如果
            我們將構造函數聲明為explicit,上面的賦值操作就會導致編譯器報錯,使我們可以及時發現錯誤.
            需要注意的是:explicit同樣也能阻止"以賦值語法進行帶有轉型操作的初始化";
            例如:
            Array arr(40);//正確
            Array arr = 40;//錯誤

            看一下以下兩種操作:
            X x;
            Y y(x);//顯式類型轉換
            另一種
            X x;
            Y y = x;//隱式類型轉換

            這兩種操作存在一個小小的差別,第一種方式式通過顯式類型轉換,根據型別x產生了型別Y的新對象;第二種方式通過隱式轉換
            產生了一個型別Y的新對象.
            explicit關鍵字的應用主要就是上面所說的構造函數定義種,參考該關鍵字的應用可以看看STL源代碼,其中大量使用了該關鍵字

            ?

            __based關鍵字


            該關鍵字主要用來解決一些和共享內存有關的問題,它允許指針被定義為從某一點開始算的32位偏移值,而不是內存種的絕對位置
            舉個例子:

            typedef struct tagDEMOSTRUCT {
            ?int a;
            ?char sz[10];
            } DEMOSTRUCT, * PDEMOSTRUCT;

            HANDLE hFileMapping = CreateFileMapping(...);
            LPVOID lpShare = (LPDWORD)MapViewOfFile(...);

            DEMOSTRUCT __based(lpShare)* lpDemo;

            上面的例子聲明了一個指針lpDemo,內部儲存的是從lpShare開始的偏移值,也就是lpHead是以lpShare為基準的偏移值.
            上面的例子種的DEMOSTRUCT只是隨便定義的一個結構,用來代表任意的結構.

            雖然__based指針使用起來非常容易,但是,你必須在效率上付出一定的代價.每當你用__based指針處理數據,CPU都必須
            為它加上基地址,才能指向真正的位置.

            在這里我只是介紹了幾個并不時很常見的關鍵字的意義即用法,其他那些常見的關鍵字介紹他們的文章已經不少了在這里
            就不再一一介紹了.希望這些內容能對大家有一定的幫助!

            posted @ 2006-10-21 13:20 Jerry Cat 閱讀(2349) | 評論 (7)編輯 收藏
            方興東抨擊博客實名制 稱此舉將摧毀中國博客

            出處:TOM科技| 2006年10月20日 14:51
            ? ?? ?? ?
            現在還不清楚博客實名制的實際情況,所以簡單評論還為時過早。但是,可以肯定的是,如果違背博客本質,違背全球互聯網基本規則,推進不合理的實名制,那么,這項政策的直接后果就是對國內博客服務造成明顯的FUD效應(擔心、疑慮和懷疑),犯下中國互聯網有史以來最大的錯誤!也是難以挽回的錯誤。

            博客用戶在失去基本安全感的情況下,首先選擇千百萬家國外的博客網站。因為,未來任何一個大型網站都將提供博客服務。除非中國全面封閉互聯網,否則選擇國外的博客服務成為中國網民的必然。

            這種不合理政策將直接摧毀中國新興的博客服務網站,成為國外博客網站市場推廣最好的方式。將造成中國博客全面向國外服務商遷移,失去一個產業的發展機會。目前,擁有千萬級博客用戶的國外博客網站,已經有10家左右。百萬級用戶的國外博客網站在數十家之多。加上各大網站都已經或者很快提供博客服務。國外博客網站將是中國實名制政策的最大贏家。變相為它們做最強有力的推廣。

            因為中國不可能讓全世界的博客網站都接受中國特色的實名制,所以國內博客網站將受到摧毀性的打擊(除非中國互聯網與世隔絕)。而更大的損失還不僅僅在于幾家博客網站本身。

            中國的博客用戶如果全面遷移到國外博客網站,被迫流浪,那么,中國互聯網將成為一座空城,中國2.0應用將失去真正用戶的家,那時候,不要說控制,就是基本的管理和引導都無從談起。未來中國的網絡社會將失去自己的網絡國民。博客在國外安家落戶,要再遷移回來其難度就不可同日而語,成本巨大!所以,今后連糾錯的機會都很難!

            所以,不符合博客發展的內在規律,不與全世界互聯網發展接軌,而出臺不合理的實名制,損害的將不僅僅是博客行業和互聯網行業,而是斷送中國整個社會和未來。

            建設好中國互聯網和博客,很不容易,但是要毀掉卻很容易。所以,我始終堅信,中國互聯網發展十年,成績輝煌。不可能會有人要苦心積慮把它摧毀掉,不可能讓發展開倒車。所以,在這個簡單的邏輯下,在實名制風雨欲來的輿論中,我始終保持樂觀心態:不合理的實名制不可能實行。

            也就是說,這個問題的本質在于:誰敢摧毀中國互聯網的發展?!其用意和出發點何在?!

            (此文來自方興東的博客)
            posted @ 2006-10-20 19:00 Jerry Cat 閱讀(400) | 評論 (1)編輯 收藏

            C++面試題集4

            一. 華為一道面試題-1-n排序

            有N個大小不等的自然數(1--N),請將它們由小到大排序。
            要求程序算法:時間復雜度為O(n),空間復雜度為O(1)。

            網上轉的,一開始也沒有注意到最開始的半句。

            算法:N個不等的自然數1~N,排序完成后必然為1~N。所以可以一次遍歷,遇到a[i]!=i的就把a[i]和a[a[i]]交換。

            void sort(int a[], int n)
            {
            ?int i;
            ?int t; /*臨時變量:空間復雜度O(1)*/

            ?for (i=1; i<n+1; i++) /*時間復雜度O(n)*/
            ?{
            ?while(a[i]!=i)
            ? {
            ?t = a[a[i]];
            ?a[a[i]] = a[i];//排好一個元素
            ?a[i] = t;
            ? }
            ?}
            }

            二. 一次遍歷 找 鏈表倒數第n個節點

            ?一道面試題目,阿明和晨晨看到并且告訴我答案的。要求通過一次遍歷找到鏈表中倒數第n個節點,鏈表可能相當大,可使用輔助空間,但是輔助空間的數目必須固定,不能和n有關。
            算法思想:兩根指針,第一根先出發,相距n步后第二根出發。然后同時步進,直到第一根指針達到末尾。

            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++學習筆記

            1.?????? 日期轉成字符串:

            ?? COleDateTime??? ww;
            ww=COleDateTime::GetCurrentTime();
            AfxMessageBox(ww.Format("%Y-%m-%d %H:%M:%S"));

            2.?????? 字符串轉成日期:

            COleDateTime dt;

            ?????? dt.ParseDateTime(“2006-08-08 08:08:08”);

            3.?????? 資源文件

            資源文件名:xxx.rc,其中要包含的主要文件:resource.h和afxres.h

            4.?????? vc開發環境沒有自動提示時:

            ?? 刪除 目錄下的ncb文件 ,再打開一般就ok了

            5.?????? 利用_variant_t 取數據庫數據的方法:

            ?? _variant_t ibb;

            ?????? ibb=(_variant_t)rs->GetCollect("inta");

            ?????? if(ibb.vt!=VT_NULL)

            ?????? {

            ????????????? m_b=ibb.lVal;

            ?????? }

            6.?????? 平時取記錄集字段值的方法:

            ?? (LPCTSTR)(_bstr_t)rs->GetCollect("datea")

            7.?????? DoModal()可以返回兩個結果 IDOK,IDCANCEL,他們都是int型,分別是:1,2。通過EndDialog(IDOK)的方式返回。

            8.?????? 一般將數據庫連接方面的信息放到app中。則AfxGetApp()非常重要,如;

            ?? CAdo2App* mapp=(CAdo2App*)AfxGetApp();

            ?? Map->conn->Execute(sql,NULL,adCmdText);

            9.?????? DECLARE_DYNCREATE(類名),IMPLEMENT_DYNCREATE(類名,基類名)? 使得由CObject繼承來的類在程序運行的時候能夠動態的創建。

            10.?? DECLARE_DYNAMIC(類名),IMPLEMENT_DYNAMIC(類名,基類名)? 可以在運行時獲得該類的信息

            11.?? DECLARE_SERIAL(類名),IMPLEMENT_SERIAL(類名,基類名,0)為一個可以串行化的CObject派生類產生必要的C++標題代碼

            12.?? 獲得文檔的方法: CMainFrame * pFrame=(CMainFrame *) AfxGetMainWnd();

            CPClientDoc * pDoc =(CPClientDoc *) pFrame->GetActiveDocument();
            ?

            13.?? 獲得視圖的方法:CMainFrame * pFrame=(CMainFrame *) AfxGetMainWnd();

            myView =(CPClientView*) pFrame->GetActiveView();

            14.?? 如果要引用全局變量或者全局方法,須在當前類中引入:extern 名字;

            posted @ 2006-10-19 21:11 Jerry Cat 閱讀(3907) | 評論 (10)編輯 收藏
                 摘要: 上一篇中我介紹了一種通過封閉Critical Section對象而方便的使用互斥鎖的方式,文中所有的例子是兩個線程對同一數據一讀一寫,因此需要讓它們在這里互斥,不能同時訪問。而在實際情況中可能會有更復雜的情況出現,就是多個線程訪問同一數據,一部分是讀,一部分是寫。我們知道只有讀-寫或寫-寫同時進行時可能會出現問題,而讀-讀則可以同時進行,因為它們不會對數據進行修改,所以也有必要在C++中封裝一種方...  閱讀全文
            posted @ 2006-10-19 14:35 Jerry Cat 閱讀(1503) | 評論 (1)編輯 收藏
                 摘要: 線程同步是多線程程序設計的核心內容,它的目的是正確處理多線程并發時的各種問題,例如線程的等待、多個線程訪問同一數據時的互斥,防死鎖等。Win32提供多種內核對象和手段用于線程同步,如互斥量、信號量、事件、臨界區等。所不同的是,互斥量、信號量、事件都是Windows的內核對象,當程序對這些對象進行控制時會自動轉換到核心態,而臨界區本身不是內核對象,它是工作在用戶態的。我們知道從用戶態轉換到核心態是需...  閱讀全文
            posted @ 2006-10-19 14:33 Jerry Cat 閱讀(1525) | 評論 (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.說出下面這個程序的運行結果,并簡要敘述其理由:

            char buf1[10]="hello";
            char buf2[10]="hello";
            if (buf1==buf2)
            printf("equal!");
            else printf("not equal!");
            因為buf1,buf2分配了不同的內存塊,而比較的是數組名,實際上是兩個分別指向數組起始元素地址的指針。

            2.指出下面這段程序中存在一些什么問題:

            int loop,a[5];
            int* p=a;
            for (loop=0;loop<5;loop++)
            { p++;
            *p=loop;
            }

            數組a[5]在創建時沒有初始化, 在for循環里也沒有起到完全初始化數組的作用,而且對一塊未知內存賦值。在最后一輪循環
            結束時p指向了數組a[5]的最后一個元素的下一個地址。

            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的構造函數
            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 的析構函數
            string::~string()
            {
            ?? delete [] m_data;
            }

            string 的拷貝構造函數
            string ::string(const string& other)
            {
            ?? int len = strlen(other.m_data);
            ?? m_data = new char[len + 1];
            ?? strcpy(m_data, other.m_data);
            }

            string 的賦值函數
            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;
            }??


            不用任何局部和全局變量實現int strlen(char *a)

            int strlen(char *a) {
            ??? if('\0' == *a)
            ??????? return 0;
            ??? else
            ??????? return 1 + strlen(a + 1);
            }


            1)sizeof相關系列問題
            2)const相關系列問題
            3)大量林銳書的習題,以及各種變種
            這三個幾乎是每次必出現
            下面的這些是程序相關題,很多都是以前有討論過的,還請各位大俠能整理個比較適合做面試時答案的解答,多謝了.最好能給出
            討論鏈接,讓我等后輩有學習的機會.
            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)寫出在母串中查找子串出現次數的代碼.
            *4)寫出快速排序或者某種排序算法代碼
            出現次數相當頻繁
            5)寫出查找從一個集合中輸出所有子集合的算法.
            *6)實現strcpy函數
            char* strcpy(char* dest, const char* src)
            {
            ?? assert((dest != NULL) && (src != NULL));
            ?? char* address = dest;
            ?? while ('\0' != (*dest++ = *src++));
            ?? return address;
            }
            出現次數相當頻繁
            *7)實現strcmp函數
            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;
            }
            ??
            出現次數相當頻繁
            8)將一個單鏈表逆序
            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)循環鏈表的節點對換和刪除。
            *10)將一個數字字符串轉換為數字."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();
            }
            出現次數相當頻繁
            11)實現任意長度的整數相加或者相乘功能。
            *12)寫函數完成內存的拷貝
            一個內存拷貝函數的實現體

            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;

            }

            出現次數相當頻繁

            ?


            .筆試:
            1)寫一個內存拷貝函數,不用任何庫函數.就是前些時候本版討論的那個問題.
            ?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)將一個單鏈表逆序.(這個問題是個常規的數據結構問題.不過不小心時會損失效率)
            3)客房預定的問題.根據客戶報的人數,客房等級來從預備的客房中選擇出所有符合要求的

            客房號.客戶沒有要求等級時,只考慮人數因素就可以了.要考慮有些客房已經預定的情況.

            (寫代碼是要考慮好彼此的效率)
            4)對于一個無序序列進行二分查找
            線排序再查找

            5)將一個數字字符串轉換為數字."1234" -->1234
            int convert(char* str)
            {
            ?? int k = 0;
            ?? while (*str != '\0')
            ?? {
            ????? k = k * 10 + *s++ - '0';
            ?? }
            ?? return k;
            }
            6)在文件(調用庫函數創建的,不用考慮數據庫的方式)中讀入信息(包括職工號,職工產量)

            .根據輸入的信息(包括職工號,職工產量)..檢測是否有相同的職工號記錄,如有,則增加其

            產量.如沒有,則創建新的記錄.最后的記錄排序的依據是職工產量(降序),如果產量相同,則

            按職工號(升序). (具體的題目記不太清了,這個題目有點長.哪位也去筆試了.請修正一下

            子)
            .
            2.面試
            1)找出兩個中文句子的相似度.(例如"中國江蘇南京" "江蘇省中國南京市".實際上是指的

            同一個地方.面試官的要求是一分鐘給出求相似度的算法.)(幸好聽老師講過中文分詞,要不

            然當場就掛了)
            2)寫出二分查找的代碼.
            3)將上述代碼通用化.(在 C 的規范內.就是我前面所的那個問題)
            4)寫出在母串中查找子串出現次數的代碼.(不顧及效率時好說.當時一不留神把 KMP 說了

            出來,結果又讓我描述整個過程.汗..只好從頭又學了.不過沒有冷場,邊學邊說.hoho)
            5)如何看待在函數中定義很多靜態變量.
            6)寫出quick_sort
            7)寫出查找從一個集合中輸出所有子集合的算法.
            8)有關于各種類型指針.各種數據類型的 sizeof 運算結果( 在 C 中)

            posted @ 2006-10-18 23:15 Jerry Cat 閱讀(2488) | 評論 (1)編輯 收藏
            僅列出標題
            共14頁: 1 2 3 4 5 6 7 8 9 Last 

            <2006年9月>
            272829303112
            3456789
            10111213141516
            17181920212223
            24252627282930
            1234567

            常用鏈接

            留言簿(7)

            隨筆檔案

            最新隨筆

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            亚洲AV无码久久精品蜜桃| 久久久久这里只有精品| 亚洲精品无码久久久影院相关影片| 久久久久久久久66精品片| 亚洲国产另类久久久精品黑人| 久久久久人妻精品一区二区三区| 精品久久久久久亚洲| 女人高潮久久久叫人喷水| 69SEX久久精品国产麻豆| 久久精品99无色码中文字幕| 亚洲人成伊人成综合网久久久| 欧美伊香蕉久久综合类网站| 2021国产精品久久精品| 亚洲综合精品香蕉久久网97| 久久久国产99久久国产一| 99久久精品国产综合一区| 亚洲色大成网站WWW久久九九| 久久国产视屏| 99久久免费国产特黄| 伊人久久大香线蕉av不变影院| 精品久久人人爽天天玩人人妻| 久久综合香蕉国产蜜臀AV| 亚洲欧洲精品成人久久奇米网| 国产精品久久影院| 久久亚洲欧美国产精品| 久久成人小视频| 欧美国产精品久久高清| 国产综合免费精品久久久| 狠狠狠色丁香婷婷综合久久俺| 久久精品国产久精国产果冻传媒 | 久久亚洲国产成人影院网站 | 久久亚洲精品成人无码网站| segui久久国产精品| 999久久久国产精品| 热re99久久精品国产99热| 久久99精品久久久久久hb无码| 亚洲中文久久精品无码ww16| 久久国产免费直播| 欧美午夜精品久久久久免费视| 天天爽天天狠久久久综合麻豆| 久久婷婷国产综合精品|