• <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>
            隨筆 - 40, 文章 - 0, 評論 - 9, 引用 - 0
            數據加載中……

            UNIX CP命令

            # 重復作兩次動作,由于 /tmp 底下已經存在 bashrc 了,加上 -i 參數,
            # 則在覆蓋前會詢問使用者是否確定!可以按下 n 或者 y 呢!
            # 但是,反過來說,如果不想要詢問時,則加上 -f 這個參數來強制直接覆蓋!

            范例二:將 /var/log/wtmp 復制到 /tmp 底下
            [root@linux tmp]# cp /var/log/wtmp . <==想要復制到目前的目錄,最后的 . 不要忘
            [root@linux tmp]# ls -l /var/log/wtmp wtmp
            -rw-rw-r--  1 root utmp 71808 Jul 18 12:46 /var/log/wtmp
            -rw-r--r--  1 root root 71808 Jul 18 21:58 wtmp
            # 注意到了嗎?!在不加任何參數的情況下,檔案的所屬者會改變,連權限也跟著改變了~
            # 這是個很重要的特性!要注意喔!還有,連檔案建立的時間也不一樣了!
            # 如果您想要將檔案的所有特性都一起復制過來,可以加上 -a 喔!
            [root@linux tmp]# cp -a /var/log/wtmp wtmp_2
            [root@linux tmp]# ls -l /var/log/wtmp wtmp_2
            -rw-rw-r--  1 root utmp 71808 Jul 18 12:46 /var/log/wtmp
            -rw-rw-r--  1 root utmp 71808 Jul 18 12:46 wtmp_2
            # 瞭了吧!整個資料特性完全一模一樣ㄟ!真是不賴~這就是 -a 的特性!

            范例三:復制 /etc/ 這個目錄下的所有內容到 /tmp 底下
            [root@linux tmp]# cp /etc/ /tmp
            cp: omitting directory `/etc'   <== 如果是目錄,不能直接復制,要加上 -r 的參數
            [root@linux tmp]# cp -r /etc/ /tmp
            # 還是要再次的強調喔! -r 是可以復制目錄,但是,檔案與目錄的權限會被改變~
            # 所以,也可以利用 cp -a /etc /tmp 來下達指令喔!

            范例四:將范例一復制的 bashrc 建立一個連結檔 (symbolic link)
            [root@linux tmp]# ls -l bashrc
            -rw-r--r--  1 root root 395 Jul 18 22:08 bashrc
            [root@linux tmp]# cp -s bashrc bashrc_slink
            [root@linux tmp]# cp -l bashrc bashrc_hlink
            [root@linux tmp]# ls -l bashrc*
            -rw-r--r--  2 root root 395 Jul 18 22:08 bashrc
            -rw-r--r--  2 root root 395 Jul 18 22:08 bashrc_hlink
            lrwxrwxrwx  1 root root   6 Jul 18 22:31 bashrc_slink -> bashrc
            # 那個 bashrc_slink 是由 -s 的參數造成的,建立的是一個『快捷方式』,
            # 所以您會看到在檔案的最右邊,會顯示這個檔案是『連結』到哪里去的!
            # 至于那個 bashrc_hlink 有趣了!建立了這個檔案之后, bashrc 與 bashrc_hlink 
            # 所有的參數都一樣,只是,第二欄的 link 數改變成為 2 了~而不是原本的 1 喔!
            # 這兩種連結的方式的異同,我們會在下一章里面進行介紹的!

            范例五:若 ~/.bashrc 比 /tmp/bashrc 新才復制過來
            [root@linux tmp]# cp -u ~/.bashrc /tmp/bashrc
            # 這個 -u 的特性,是在目標檔案與來源檔案有差異時,才會復制的。
            # 所以,比較常被用于『備份』的工作當中喔! ^_^

            范例六:將范例四造成的 bashrc_slink 復制成為 bashrc_slink_2
            [root@linux tmp]# cp bashrc_slink bashrc_slink_2
            [root@linux tmp]# ls -l bashrc_slink*
            lrwxrwxrwx  1 root root   6 Jul 18 22:31 bashrc_slink -> bashrc
            -rw-r--r--  1 root root 395 Jul 18 22:48 bashrc_slink_2
            # 這個例子也是很有趣喔!原本復制的是連結檔,但是卻將連結檔的實際檔案復制過來了
            # 也就是說,如果沒有加上任何參數時,復制的是源文件,而非連結文件的屬性!
            # 若要復制連結文件的屬性,就得要使用 -d 或者 -a 的參數了!

            范例七:將家目錄的 .bashrc 及 .bash_history 復制到 /tmp 底下
            [root@linux tmp]# cp ~/.bashrc ~/.bash_history /tmp
            # 可以將多個數據一次復制到同一個目錄去!
            這個 cp 的功能很多,而由于我們常常在進行一些數據的復制,所以也會常常用到這個指令的。 一般來說,我們如果去復制別人的數據 (當然,該檔案您必須要有 read 的權限才行啊! ^_^) 時, 總是希望復制到的數據最后是我們自己的,所以,在預設的條件中, cp 的來源檔與目的檔的權限是不同的,目的檔的擁有者通常會是指令操作者本身。舉例來說, 上面的范例二中,由于我是 root 的身份,因此復制過來的檔案擁有者與群組就改變成為 root 所有了! 這樣說,可以明白嗎?! ^_^

            由于具有這個特性,因此,當我們在進行備份的時候,某些需要特別注意的特殊權限檔案, 例如密碼文件 (/etc/shadow) 以及一些設定檔,就不能直接以 cp 來復制,而必須要加上 -a 或者是 -p 等等可以完整復制檔案權限的參數才行!另外,如果您想要復制檔案給其它的使用者, 也必須要注意到檔案的權限(包含讀、寫、執行以及檔案擁有者等等), 否則,其它人還是無法針對您給予的檔案進行修訂的動作喔!注意注意!

            至于上面的范例當中,第四個范例是最有趣的,使用 -l 及 -s 都會建立所謂的連結檔 (link file), 但是這兩種連結檔確有不一樣的展現情況。這是怎么一回事啊? 那個 -l 就是所謂的 hard link ,至于 -s 則是 symbolic link ,鳥哥這里先不介紹, 因為這個涉及 i-node 的相關知識,我們還沒有介紹到,下一章再來討論這個 link 的問題喔! 總之,由于 cp 有種種的檔案屬性與權限的特性,所以,在復制時,您必須要清楚的了解到: 
            • 是否需要完整的保留來源檔案的信息? 
            • 來源檔案是否為連結檔 (symbolic link file)? 
            • 來源檔是否為特殊的檔案,例如 FIFO, socket 等? 
            • 來源文件是否為目錄?

            posted @ 2008-01-02 11:56 茶 閱讀(8454) | 評論 (0)編輯 收藏

            SQL語言簡介

                 摘要: 1、           SQL概述 SQL是一種面向數據庫的通用數據處理語言規范,能完成以下幾類功能:提取查詢數據,插入修改刪除數據,生成修改和刪除數據庫對象,數據庫安全控制,數據庫完整性及數據保護控制。 數據庫對象包括表、視圖、索引、同義詞、簇、觸發器、函數、過程、包、數據庫鏈、快照等(表空...  閱讀全文

            posted @ 2007-12-29 17:25 茶 閱讀(260) | 評論 (0)編輯 收藏

            用Pro*C開發多線程應用程序 (1)

            (注:本文來自Pro*C/C++ Precompiler Programmer's Guide Release 8.1.5) 
              
              如果你的操作系統不支持線程,本文暫不適合你。本文包含以下幾個部分: 
              
              n 什么是多線程? 
              
              n Pro*C中的運行時上下文 
              
              n 運行時上下文的使用模式 
              
              n 多線程應用程序的用戶接口 
              
              n 多線程例子 
              
              一.什么是多線程? 
              一個多線程的應用程序中,線程運行在共享的地址空間里。線程是在進程內部執行的“輕量”級子進程,它們共享代碼段和數據段,但是有自己的程序計數器、寄存器和堆棧。全局變量和靜態變量在線程之間是共享的,因此通常需要在程序中使用某種互斥機制來管理線程對這些變量的訪問,互斥體Mutexes就是用來保證數據完整性的同步裝置。 
              
              有關互斥體的更多討論,參看多線程編程方面的文章。 
              
              Proc*C編譯器通過以下方式支持開發多線程的Oracle應用程序(在支持線程的平臺上): 
              
              n 用一個命令行編譯選項來產生線程安全的代碼 
              
              n 用內嵌的SQL語句和指令支持多線程 
              
              n 線程安全的Lib庫和其他客戶端Lib庫 
              
              注意:也許你的平臺支持某個特殊的線程包,但還是需要查看Oracle有關平臺的文檔,看看Oracle是否支持它。 
              
              二.Pro*C中的運行時上下文 
              為了在線程和數據庫連接之間建立松散的結合,Pro*C引入了一個概念runtime_context,我們稱之為運行時上下文。一個運行時上下文包含了以下資源和信息: 
              
              n 與數據庫服務器的連接 
              
              n 當前連接上使用的游標 
              
              n 內嵌的一些選項,如MODE,HOLD_CURSOR,RELEASE_CURSOR和 SELECT_ERROR 
              
              不僅僅是簡單的支持線程和連接之間的松散結合,Pro*C編譯器還允許開發人員在線程和運行時上下文之間建立松散的結合,Pro*C允許在程序里為運行時上下文定義一個句柄,通過這個句柄,運行時上下文可以在線程之間切換。 
              
              例如,一個交互式應用程序創建了線程T1,來執行一個查詢,并且返回了前10條記錄,然后T1終止。在用戶輸入了必須的數據之后,程序又創建了線程T2,并且把T1使用的運行時上下文傳給T2,這樣T2可以在同一個游標上獲取接下來10條的記錄。 
              
              三.運行時上下文的使用模式 
              下面是在多線程的Pro*C程序中使用運行時上下文的兩種可能模式: 
              
              n 多線程共享單個運行時上下文 
              
              n 多線程使用互相獨立的運行時上下文 
              
              不管采用哪種模式,不能在同一時刻多個線程共享同一個運行時上下文。如果兩個或兩個以上的線程在同一時刻試圖使用同一個運行時上下文,將會出現以下錯誤:SQL-02131: Runtime context in use。 
              
              1.多線程共享單個運行時上下文 
              
              2.多線程使用互相獨立的運行時上下文 
              
              四.多線程應用程序的用戶接口 
              Pro*C編譯器提供以下接口來支持多線程: 
              
              n 命令行選項,THREADS=YES|NO 
              
              n 內嵌SQL語句和指令 
              
              n 線程安全的公共庫函數 
              
              1.THREADS選項 
              在proc預編譯命令行上指定THREADS=YES,Pro*C編譯器將保證產生的C代碼是線程安全的。如果指定了THREADS=YES,Pro*C將會檢查每個包含SQL執行語句的函數,是否指定了這些語句是在哪個運行時上下文中執行的,若沒有發現這類指定標識,編譯器就會返回錯誤。 
              
              2.內嵌SQL語句和指令 
              下列內嵌的SQL語句和指令用于支持多線程和運行時上下文的使用: 
              
              n EXEC SQL ENABLE THREADS; 
              
              n EXEC SQL CONTEXT ALLOCATE :context_var; 
              
              n EXEC SQL CONTEXT USE {:context_var/DEFAULT}; 
              
              n EXEC SQL CONTEXT FREE :context_var; 
              
              在以上SQL語句中,context_var是運行時上下文句柄,它必須被定義成sql_context類型:如sql_context context_var; 
              
              使用DEFAULT意味著接下來的SQL語句將使用默認的全局運行時上下文,直到另一條CONTEXT USE語句覆蓋它。 
              
              n EXEC SQL ENABLE THREADS 
              
              這條可執行SQL語句初始化支持多線程的進程。它必須是程序中第一條可執行的SQL語句。 
              
              n EXEC SQL CONTEXT ALLOCATE 
              
              這條可執行SQL語句分配并初始化了一塊用于指向一個新的運行時上下文的內存,并返回標識該上下文的句柄變量,該變量必須聲明為sql_context類型。 
              
              n EXEC SQL CONTEXT USE 
              
              這條指令性語句告訴編譯器接下去執行的SQL語句將使用指定的運行時上下文,這里的運行時上下文必須在此前已經用CONTEXT ALLOCATE分配并初始化。 
              
              n EXEC SQL CONTEXT FREE 
              
              這條語句釋放了運行時上下文句柄指定的內存,并把它設置空值。 
              
              3.編程時要考慮的問題 
              盡管Oracle保證SQL庫是線程安全的,但是你還是有責任保證你的Pro*C代碼是為能在多線程下正確運行而設計的,例如,你必須考慮全局變量和靜態變量的。 
              
              另外,多線程要求對以下問題進行考慮: 
              
              n 把sqlca結構定義成線程安全的。典型的做法是在每個函數開始定義一個同名的局部變量。 
              
              n sqlda結構也和sqlca結構一樣處理。 
              
              n 把程序里的宿主變量定義成線程安全的。也就是說要小心處理程序里的全局變量和靜態變量。 
              
              n 避免同一時刻不同線程使用同一個運行時上下文。 
              
              五.多線程例子 
              下面的例子運行在Red Hat9和Oracle9上。程序目的是用兩個線程同時往一個表里插10000條記錄,每個線程都擁有自己的運行時上下文。 
              
              #include 
              
              #include 
              
              #include /* Linux線程
          1. 頭文件 */ 
              
              #include "sqlca.h" /* Oracle頭文件 */ 
              
              #define SQLCODE sqlca.sqlcode 
              
              static int insert_data( sql_context ); 
              
              static int start(); 
              
              int 
              
              main() 
              
              { 
              
              pthread_t tid1, tid2; 
              
              /* 創建兩個線程 */ 
              
              if( pthread_create( &tid1,NULL,(void *)start,NULL ) ){ 
              
              printf( "創建線程失敗!\n" ); 
              
              exit(1); 
              
              } 
              
              if( pthread_create( &tid2,NULL,(void *)start,NULL ) ){ 
              
              printf( "創建線程失敗!\n" ); 
              
              exit(1); 
              
              } 
              
              /* 等待線程退出 */ 
              
              if( pthread_join( tid1,NULL ) ){ 
              
              printf( "等待線程結束失敗!\n" ); 
              
              exit(1); 
              
              } 
              
              if( pthread_join( tid2,NULL ) ){ 
              
              printf( "等待線程結束失敗!\n" ); 
              
              exit(1); 
              
              } 
              
              exit(0); 
              
              } 
              
              
              int 
              
              start() 
              
              { 
              
              sql_context context; 
              
              struct sqlca sqlca; /* 需要在此定義一個局部的sqlca */ 
              
              char uid[] = "dev/888888"; 
              /* 以下SQL語句的執行順序不能更改 */ 
              
              EXEC SQL ENABLE THREADS; 
              
              EXEC SQL CONTEXT ALLOCATE :context; 
              
              EXEC SQL CONTEXT USE :context; 
              
              EXEC SQL CONNECT :uid; 
              
              if( SQLCODE < 0 ){ 
              
              printf( "創建數據庫連接失敗,%d:%s\n", SQLCODE,sqlca.sqlerrm.sqlerrmc); 
              
              return -1; 
              
              }insert_data( context ); 
              
              EXEC SQL COMMIT WORK RELEASE; 
              
              if( SQLCODE < 0 ){ 
              
              printf( "斷開數據庫連接失敗!%d:%s\n", SQLCODE,sqlca.sqlerrm.sqlerrmc ); 
              
              return -1; 
              
              } 
              
              EXEC SQL CONTEXT FREE :context; 
              
              return 0; 
              
              } 
              
              static int 
              
              insert_data( context ) 
              
              sql_context context; 
              
              { 
              
              struct sqlca sqlca; /* 需要在此定義一個局部的sqlca */ 
              
              char name[11]; 
              
              int age; 
              
              int i; 
              
              strcpy( name, "test" ); 
              
              age = 20; 
              
              
              
              EXEC SQL CONTEXT USE :context; /* 指定執行SQL語句的上下文 */ 
              
              for( i=0; i
          2. posted @ 2007-12-29 16:23 茶 閱讀(294) | 評論 (0)編輯 收藏

            typedef

             
            typedef用法小結- -
            這兩天在看程序的時候,發現很多地方都用到typedef,在結構體定義,還有一些數組等地方都大量的用到.但是有些地方還不是很清楚,今天下午,就想好好研究一下.上網搜了一下,有不少資料.歸納一下:
            來源一:Using typedef to Curb Miscreant Code
            Typedef 聲明有助于創建平臺無關類型,甚至能隱藏復雜和難以理解的語法。不管怎樣,使用 typedef 能為代碼帶來意想不到的好處,通過本文你可以學習用 typedef 避免缺欠,從而使代碼更健壯。
            typedef 聲明,簡稱 typedef,為現有類型創建一個新的名字。比如人們常常使用 typedef 來編寫更美觀和可讀的代碼。所謂美觀,意指 typedef 能隱藏笨拙的語法構造以及平臺相關的數據類型,從而增強可移植性和以及未來的可維護性。本文下面將竭盡全力來揭示 typedef 強大功能以及如何避免一些常見的陷阱。
            如何創建平臺無關的數據類型,隱藏笨拙且難以理解的語法?
            使用 typedefs 為現有類型創建同義字。
            定義易于記憶的類型名
              typedef 使用最多的地方是創建易于記憶的類型名,用它來歸檔程序員的意圖。類型出現在所聲明的變量名字中,位于 ''typedef'' 關鍵字右邊。例如:
            typedef int size;
              此聲明定義了一個 int 的同義字,名字為 size。注意 typedef 并不創建新的類型。它僅僅為現有類型添加一個同義字。你可以在任何需要 int 的上下文中使用 size:
            void measure(size * psz);
            size array[4];
            size len = file.getlength();
            std::vector vs;
              typedef 還可以掩飾符合類型,如指針和數組。例如,你不用象下面這樣重復定義有 81 個字符元素的數組:
            char line[81];
            char text[81];
            定義一個 typedef,每當要用到相同類型和大小的數組時,可以這樣:
            typedef char Line[81];
            Line text, secondline;
            getline(text);
            同樣,可以象下面這樣隱藏指針語法:
            typedef char * pstr;
            int mystrcmp(pstr, pstr);
              這里將帶我們到達第一個 typedef 陷阱。標準函數 strcmp()有兩個‘const char *'類型的參數。因此,它可能會誤導人們象下面這樣聲明 mystrcmp():
            int mystrcmp(const pstr, const pstr);
              這是錯誤的,按照順序,‘const pstr'被解釋為‘char * const'(一個指向 char 的常量指針),而不是‘const char *'(指向常量 char 的指針)。這個問題很容易解決:
            typedef const char * cpstr;
            int mystrcmp(cpstr, cpstr); // 現在是正確的
            記住:不管什么時候,只要為指針聲明 typedef,那么都要在最終的 typedef 名稱中加一個 const,以使得該指針本身是常量,而不是對象。
            代碼簡化
              上面討論的 typedef 行為有點像 #define 宏,用其實際類型替代同義字。不同點是 typedef 在編譯時被解釋,因此讓編譯器來應付超越預處理器能力的文本替換。例如:
            typedef int (*PF) (const char *, const char *);
              這個聲明引入了 PF 類型作為函數指針的同義字,該函數有兩個 const char * 類型的參數以及一個 int 類型的返回值。如果要使用下列形式的函數聲明,那么上述這個 typedef 是不可或缺的:
            PF Register(PF pf);
              Register() 的參數是一個 PF 類型的回調函數,返回某個函數的地址,其署名與先前注冊的名字相同。做一次深呼吸。下面我展示一下如果不用 typedef,我們是如何實現這個聲明的:
            int (*Register (int (*pf)(const char *, const char *)))
            (const char *, const char *);
              很少有程序員理解它是什么意思,更不用說這種費解的代碼所帶來的出錯風險了。顯然,這里使用 typedef 不是一種特權,而是一種必需。持懷疑態度的人可能會問:"OK,有人還會寫這樣的代碼嗎?",快速瀏覽一下揭示 signal()函數的頭文件 ,一個有同樣接口的函數。
            typedef 和存儲類關鍵字(storage class specifier)
              這種說法是不是有點令人驚訝,typedef 就像 auto,extern,mutable,static,和 register 一樣,是一個存儲類關鍵字。這并是說 typedef 會真正影響對象的存儲特性;它只是說在語句構成上,typedef 聲明看起來象 static,extern 等類型的變量聲明。下面將帶到第二個陷阱:
            typedef register int FAST_COUNTER; // 錯誤
              編譯通不過。問題出在你不能在聲明中有多個存儲類關鍵字。因為符號 typedef 已經占據了存儲類關鍵字的位置,在 typedef 聲明中不能用 register(或任何其它存儲類關鍵字)。
            促進跨平臺開發
              typedef 有另外一個重要的用途,那就是定義機器無關的類型,例如,你可以定義一個叫 REAL 的浮點類型,在目標機器上它可以i獲得最高的精度:
            typedef long double REAL;
            在不支持 long double 的機器上,該 typedef 看起來會是下面這樣:
            typedef double REAL;
            并且,在連 double 都不支持的機器上,該 typedef 看起來會是這樣:、
            typedef float REAL;
               你不用對源代碼做任何修改,便可以在每一種平臺上編譯這個使用 REAL 類型的應用程序。唯一要改的是 typedef 本身。在大多數情況下,甚至這個微小的變動完全都可以通過奇妙的條件編譯來自動實現。不是嗎? 標準庫廣泛地使用 typedef 來創建這樣的平臺無關類型:size_t,ptrdiff 和 fpos_t 就是其中的例子。此外,象 std::string 和 std::ofstream 這樣的 typedef 還隱藏了長長的,難以理解的模板特化語法,例如:basic_string,allocator> 和 basic_ofstream>。
            作者簡介
              Danny Kalev 是一名通過認證的系統分析師,專攻 C++ 和形式語言理論的軟件工程師。1997 年到 2000 年期間,他是 C++ 標準委員會成員。最近他以優異成績完成了他在普通語言學研究方面的碩士論文。業余時間他喜歡聽古典音樂,閱讀維多利亞時期的文學作品,研究 Hittite、Basque 和 Irish Gaelic 這樣的自然語言。其它興趣包括考古和地理。Danny 時常到一些 C++ 論壇并定期為不同的 C++ 網站和雜志撰寫文章。他還在教育機構講授程序設計語言和應用語言課程。
            來源二:(http://www.ccfans.net/bbs/dispbbs.asp?boardid=30&;id=4455)
            C語言中typedef用法
            1. 基本解釋
              typedef為C語言的關鍵字,作用是為一種數據類型定義一個新名字。這里的數據類型包括內部數據類型(int,char等)和自定義的數據類型(struct等)。
              在編程中使用typedef目的一般有兩個,一個是給變量一個易記且意義明確的新名字,另一個是簡化一些比較復雜的類型聲明。
              至于typedef有什么微妙之處,請你接著看下面對幾個問題的具體闡述。
             2. typedef & 結構的問題
              當用下面的代碼定義一個結構時,編譯器報了一個錯誤,為什么呢?莫非C語言不允許在結構中包含指向它自己的指針嗎?請你先猜想一下,然后看下文說明:
            typedef struct tagNode
            {
             char *pItem;
             pNode pNext;
            } *pNode;
              答案與分析:
              1、typedef的最簡單使用
            typedef long byte_4;
              給已知數據類型long起個新名字,叫byte_4。
              2、 typedef與結構結合使用
            typedef struct tagMyStruct
            {
             int iNum;
             long lLength;
            } MyStruct;
              這語句實際上完成兩個操作:
              1) 定義一個新的結構類型
            struct tagMyStruct
            {
             int iNum;
             long lLength;
            };
              分析:tagMyStruct稱為“tag”,即“標簽”,實際上是一個臨時名字,struct 關鍵字和tagMyStruct一起,構成了這個結構類型,不論是否有typedef,這個結構都存在。
              我們可以用struct tagMyStruct varName來定義變量,但要注意,使用tagMyStruct varName來定義變量是不對的,因為struct 和tagMyStruct合在一起才能表示一個結構類型。
              2) typedef為這個新的結構起了一個名字,叫MyStruct。
            typedef struct tagMyStruct MyStruct;
              因此,MyStruct實際上相當于struct tagMyStruct,我們可以使用MyStruct varName來定義變量。
              答案與分析
              C語言當然允許在結構中包含指向它自己的指針,我們可以在建立鏈表等數據結構的實現上看到無數這樣的例子,上述代碼的根本問題在于typedef的應用。
              根據我們上面的闡述可以知道:新結構建立的過程中遇到了pNext域的聲明,類型是pNode,要知道pNode表示的是類型的新名字,那么在類型本身還沒有建立完成的時候,這個類型的新名字也還不存在,也就是說這個時候編譯器根本不認識pNode。
              解決這個問題的方法有多種:
              1)、
            typedef struct tagNode
            {
             char *pItem;
             struct tagNode *pNext;
            } *pNode;
              2)、
            typedef struct tagNode *pNode;
            struct tagNode
            {
             char *pItem;
             pNode pNext;
            };
              注意:在這個例子中,你用typedef給一個還未完全聲明的類型起新名字。C語言編譯器支持這種做法。
              3)、規范做法:
            struct tagNode
            {
             char *pItem;
             struct tagNode *pNext;
            };
            typedef struct tagNode *pNode;
             3. typedef & #define的問題
              有下面兩種定義pStr數據類型的方法,兩者有什么不同?哪一種更好一點?
            typedef char *pStr;
            #define pStr char *;
              答案與分析:
              通常講,typedef要比#define要好,特別是在有指針的場合。請看例子:
            typedef char *pStr1;
            #define pStr2 char *;
            pStr1 s1, s2;
            pStr2 s3, s4;
              在上述的變量定義中,s1、s2、s3都被定義為char *,而s4則定義成了char,不是我們所預期的指針變量,根本原因就在于#define只是簡單的字符串替換而typedef則是為一個類型起新名字。
              #define用法例子:
            #define f(x) x*x
            main( )
            {
             int a=6,b=2,c;
             c=f(a) / f(b);
             printf("%d \\n",c);
            }
              以下程序的輸出結果是: 36。
              因為如此原因,在許多C語言編程規范中提到使用#define定義時,如果定義中包含表達式,必須使用括號,則上述定義應該如下定義才對:
            #define f(x) (x*x)
              當然,如果你使用typedef就沒有這樣的問題。
              4. typedef & #define的另一例
              下面的代碼中編譯器會報一個錯誤,你知道是哪個語句錯了嗎?
            typedef char * pStr;
            char string[4] = "abc";
            const char *p1 = string;
            const pStr p2 = string;
            p1++;
            p2++;
              答案與分析:
              是p2++出錯了。這個問題再一次提醒我們:typedef和#define不同,它不是簡單的文本替換。上述代碼中const pStr p2并不等于const char * p2。const pStr p2和const long x本質上沒有區別,都是對變量進行只讀限制,只不過此處變量p2的數據類型是我們自己定義的而不是系統固有類型而已。因此,const pStr p2的含義是:限定數據類型為char *的變量p2為只讀,因此p2++錯誤。
              #define與typedef引申談
              1) #define宏定義有一個特別的長處:可以使用 #ifdef ,#ifndef等來進行邏輯判斷,還可以使用#undef來取消定義。
              2) typedef也有一個特別的長處:它符合范圍規則,使用typedef定義的變量類型其作用范圍限制在所定義的函數或者文件內(取決于此變量定義的位置),而宏定義則沒有這種特性。
              5. typedef & 復雜的變量聲明
              在編程實踐中,尤其是看別人代碼的時候,常常會遇到比較復雜的變量聲明,使用typedef作簡化自有其價值,比如:
              下面是三個變量的聲明,我想使用typdef分別給它們定義一個別名,請問該如何做?
            >1:int *(*a[5])(int, char*);
            >2:void (*b[10]) (void (*)());
            >3. doube(*)() (*pa)[9];
              答案與分析:
              對復雜變量建立一個類型別名的方法很簡單,你只要在傳統的變量聲明表達式里用類型名替代變量名,然后把關鍵字typedef加在該語句的開頭就行了。
            >1:int *(*a[5])(int, char*);
            //pFun是我們建的一個類型別名
            typedef int *(*pFun)(int, char*);
            //使用定義的新類型來聲明對象,等價于int* (*a[5])(int, char*);
            pFun a[5];
            >2:void (*b[10]) (void (*)());
            //首先為上面表達式藍色部分聲明一個新類型
            typedef void (*pFunParam)();
            //整體聲明一個新類型
            typedef void (*pFun)(pFunParam);
            //使用定義的新類型來聲明對象,等價于void (*b[10]) (void (*)());
            pFun b[10];
            >3. doube(*)() (*pa)[9];
            //首先為上面表達式藍色部分聲明一個新類型
            typedef double(*pFun)();
            //整體聲明一個新類型
            typedef pFun (*pFunParam)[9];
            //使用定義的新類型來聲明對象,等價于doube(*)() (*pa)[9];
            pFunParam pa;

            #define S(s) printf("%s\n", #s); s

             

            typedef struct _TS1{

                int x, y;

            } TS1, *PTS1, ***PPPTS1;  // TS1是結構體的名稱,PTS1是結構體指針的名稱

            // 也就是將結構體struct _TS1 命名為TS1,

            // struct _TS1 * 命名為 PTS1

            // struct _TS1 *** 命名為 PPPTS1

             

            typedef struct { // struct后面的結構體說明也可以去掉

                int x, y;

            } TS2, *PTS2;

             

            typedef PTS1 *PPTS1; // 定義PPTS1是指向PTS1的指針

             

            typedef struct _TTS1{

                typedef struct ITTS1 {

                    int x, y;

                } iner;

                iner i;

                int x, y;

            } TTS1;

             

            //結構體內部的結構體也一樣可以定義

            typedef TTS1::ITTS1 ITS1;

             

            void test_struct()

            {

                // 基本結構體重定義的使用

                TS1 ts1 = {100, 200};

                PTS1 pts1 = &ts1; // 完全等價于TS1* pts1 = &ts1;

                PPTS1 ppts1 = &pts1; // 完全等價于TS1** ppts1 = &pts1;

                PPPTS1 pppts1 = &ppts1; // 完全等價于 TS1*** pppts1 = &ppts1;

             

                TS2 ts2 = {99, 88};

                PTS2 pts2 = &ts2;   // 完全等價于 TS2* pts2 = &ts2;

             

                TTS1 itts1 = {{110, 220}, 10, 20};

                Its1* rits1 = &itts1.i;

                ITS1* &its1 = rits1; // 等價于 TTS1::ITTS1 *its1 = &(itts1.i);

             

                printf("ts1\t = (%d, %d)\n*pts1\t = (%d, %d)\n"

                       "**ppts1\t = (%d, %d)\n***pppts1= (%d, %d)\n\n",

                        ts1.x, ts1.y, pts1->x, pts1->y,

                        (**ppts1).x, (**ppts1).y, (***pppts1).x, (***pppts1).y);

                printf("ts2\t = (%d, %d)\n*pts2\t = (%d, %d)\n\n",

                    ts2.x, ts2.y, pts2->x, pts2->y);

                printf("itts1\t = [(%d, %d), %d, %d]\n*its1\t =  (%d, %d)\n\n",

                    itts1.i.x, itts1.i.y, itts1.x, itts1.y, its1->x, its1->y);

             

                S(pts1->x = 119);

                S(pts2->y = 911);

                S(its1->x = 999);

             

                printf("ts1\t = (%d, %d)\n*pts1\t = (%d, %d)\n"

                       "**ppts1\t = (%d, %d)\n***pppts1= (%d, %d)\n\n",

                        ts1.x, ts1.y, pts1->x, pts1->y,

                        (**ppts1).x, (**ppts1).y, (***pppts1).x, (***pppts1).y);

                printf("ts2\t = (%d, %d)\n*pts2\t = (%d, %d)\n\n",

                    ts2.x, ts2.y, pts2->x, pts2->y);

                printf("itts1\t = [(%d, %d), %d, %d]\n*its1\t =  (%d, %d)\n\n",

                    itts1.i.x, itts1.i.y, itts1.x, itts1.y, its1->x, its1->y);

             

                S((*ppts1)->y = -9999);

                printf("ts1\t = (%d, %d)\n**ppts1\t = (%d, %d)\n\n",

                    ts1.x, ts1.y, (*ppts1)->x, (*ppts1)->y);

             

                S((**pppts1)->x = -12345);

                S((***pppts1).y = -67890);

                printf("ts1\t = (%d, %d)\n*pts1\t = (%d, %d)\n"

                       "**ppts1\t = (%d, %d)\n***pppts1= (%d, %d)\n\n",

                        ts1.x, ts1.y, pts1->x, pts1->y,

                        (**ppts1).x, (**ppts1).y, (***pppts1).x, (***pppts1).y);

            }

            posted @ 2007-12-25 09:33 茶 閱讀(448) | 評論 (0)編輯 收藏

            unix多進程2

            linux下的多進程編程(2007-5-21,11:17:55)
            什么是一個進程?進程這個概念是針對系統而不是針對用戶的,對用戶來說,他面對的概念是程序。當用戶敲入命令執行一個程序的時候,對系統而言,它將啟動一個進程。但和程序不同的是,在這個進程中,系統可能需要再啟動一個或多個進程來完成獨立的多個任務。多進程編程的主要內容包括進程控制和進程間通信,在了解這些之前,我們先要簡單知道進程的結構。
            2.1 Linux下進程的結構
            Linux下一個進程在內存里有三部分的數據,就是"代碼段"、"堆棧段"和"數據段".其實學過匯編語言的人一定知道,一般的CPU都有上述三種段寄存器,以方便操作系統的運行。這三個部分也是構成一個完整的執行序列的必要的部分。
            "代碼段",顧名思義,就是存放了程序代碼的數據,假如機器中有數個進程運行相同的一個程序nokia s40 主題下載,那么它們就可以使用相同的代碼段。"堆棧段"存放的就是子程序的返回地址、子程序的參數以及程序的局部變量。而數據段則存放程序的全局變量,常數以及動態數據分配的數據空間(比如用malloc之類的函數取得的空間)。這其中有許多細節問題,這里限于篇幅就不多介紹了。系統如果同時運行數個相同的程序,它們之間就不能使用同一個堆棧段和數據段。
            2.2 Linux下的進程控制
            在傳統的Unix環境下,有兩個基本的操作用于創建和修改進程:函數fork( )用來創建一個新的進程,該進程幾乎是當前進程的一個完全拷貝;函數族exec( )用來啟動另外的進程以取代當前運行的進程。Linux的進程控制和傳統的Unix進程控制基本一致,只在一些細節的地方有些區別手機和絢鈴聲,例如在Linux系統中調用vfork和fork完全相同,而在有些版本的Unix系統中,vfork調用有不同的功能。由于這些差別幾乎不影響我們大多數的編程,在這里我們不予考慮。
            2.2.1 fork( )
            fork在英文中是"分叉"的意思。為什么取這個名字呢?因為一個進程在運行中,如果使用了fork,就產生了另一個進程,于是進程就"分叉"了,所以這個名字取得很形象。下面就看看如何具體使用fork,這段程序演示了使用fork的基本框架:
            void main(){
            int i;
            if ( fork() == 0 ) {
            /* 子進程程序 */
            for ( i = 1; i <1000; i ++ ) printf("This is child process ");
            }
            else {
            /* 父進程程序*/
            for ( i = 1; i <1000; i ++ ) printf("This is process process ");
            }
            }
            程序運行后,你就能看到屏幕上交替出現子進程與父進程各打印出的一千條信息了。如果程序還在運行中,你用ps命令就能看到系統中有兩個它在運行了。 那么調用這個fork函數時發生了什么呢?fork函數啟動一個新的進程,前面我們說過,這個進程幾乎是當前進程的一個拷貝:子進程和父進程使用相同的代碼段;子進程復制父進程的堆棧段和數據段。這樣,父進程的所有數據都可以留給子進程,但是,子進程一旦開始運行,雖然它繼承了父進程的一切數據,但實際上數據卻已經分開,相互之間不再有影響了,也就是說,它們之間不再共享任何數據了。它們再要交互信息時,只有通過進程間通信來實現,這將是我們下面的內容。既然它們如此相象,系統如何來區分它們呢?這是由函數的返回值來決定的。對于父進程,fork函數返回了子程序的進程號,而對于子程序中興小靈通來電彩鈴,fork函數則返回零。在操作系統中,我們用ps函數就可以看到不同的進程號,對父進程而言,它的進程號是由比它更低層的系統調用賦予的,而對于子進程而言,它的進程號即是fork函數對父進程的返回值。在程序設計中,父進程和子進程都要調用函數fork()下面的代碼nokia 7650 鈴聲,而我們就是利用fork()函數對父子進程的不同返回值用if……else……語句來實現讓父子進程完成不同的功能,正如我們上面舉的例子一樣。我們看到,上面例子執行時兩條信息是交互無規則的打印出來的cect鈴聲下載,這是父子進程獨立執行的結果,雖然我們的代碼似乎和串行的代碼沒有什么區別。 讀者也許會問,如果一個大程序在運行中,它的數據段和堆棧都很大,一次fork就要復制一次,那么fork的系統開銷不是很大嗎?其實UNIX自有其解決的辦法,大家知道,一般CPU都是以"頁"為單位來分配內存空間的,每一個頁都是實際物理內存的一個映像,象INTEL的CPU,其一頁在通常情況下是4086字節大小,而無論是數據段還是堆棧段都是由許多"頁"構成的,fork函數復制這兩個段,只是"邏輯"上的,并非"物理"上的,也就是說,實際執行fork時,物理空間上兩個進程的數據段和堆棧段都還是共享著的,當有一個進程寫了某個數據時,這時兩個進程之間的數據才有了區別,系統就將有區別的"頁"從物理上也分開。系統在空間上的開銷就可以達到最小。
               下面演示一個足以"搞死"Linux的小程序,其源代碼非常簡單:
              void main()
               {
                 for( ; ; ) fork();
               }
              這個程序什么也不做,就是死循環地fork,其結果是程序不斷產生進程,而這些進程又不斷產生新的進程,很快,系統的進程就滿了,系統就被這么多不斷產生的進程"撐死了"。當然只要系統管理員預先給每個用戶設置可運行的最大進程數,這個惡意的程序就完成不了企圖了。
               2.2.2 exec( )函數族
              下面我們來看看一個進程如何來啟動另一個程序的執行。在Linux中要使用exec函數族。系統調用execve()對當前進程進行替換,替換者為一個指定的程序,其參數包括文件名(filename)、參數列表(argv)以及環境變量(envp)。exec函數族當然不止一個,但它們大致相同,在Linux中,它們分別是:execl,execlp搞笑寶寶彩鈴,execle,execv,execve和execvp,下面我只以execlp為例,其它函數究竟與execlp有何區別,請通過manexec命令來了解它們的具體情況。
              一個進程一旦調用exec類函數,它本身就"死亡"了,系統把代碼段替換成新的程序的代碼,廢棄原有的數據段和堆棧段,并為新程序分配新的數據段與堆棧段,唯一留下的,就是進程號,也就是說,對系統而言,還是同一個進程,不過已經是另一個程序了。(不過exec類函數中有的還允許繼承環境變量之類的信息。)
              那么如果我的程序想啟動另一程序的執行但自己仍想繼續運行的話,怎么辦呢?那就是結合fork與exec的使用。下面一段代碼顯示如何啟動運行其它程序:char command[256];
            void main()
            {
            int rtn; /*子進程的返回數值*/
            while(1) {
            /* 從終端讀取要執行的命令 */
            printf( ">" );
            fgets( command, 256, stdin );
            command[strlen(command)-1] = 0;
            if ( fork() == 0 ) {
            /* 子進程執行此命令 */
            execlp( command, command );
            /* 如果exec函數返回,表明沒有正常執行命令,打印錯誤信息*/
            perror( command );
            exit( errorno );
            }
            else {
            /* 父進程, 等待子進程結束,并打印子進程的返回值 */
            wait ( &rtn );
            printf( " child process return %d ",. rtn );
            }
            }
            }
              此程序從終端讀入命令并執行之,執行完成后,父進程繼續等待從終端讀入命令。熟悉DOS和WINDOWS系統調用的朋友一定知道DOS/WINDOWS也有exec類函數,其使用方法是類似的天津聯通鈴音下載,但DOS/WINDOWS還有spawn類函數,因為DOS是單任務的系統,它只能將"父進程"駐留在機器內再執行"子進程",這就是spawn類的函數。WIN32已經是多任務的系統了,但還保留了spawn類函數,WIN32中實現spawn函數的方法同前述UNIX中的方法差不多,開設子進程后父進程等待子進程結束后才繼續運行。UNIX在其一開始就是多任務的系統,所以從核心角度上講不需要spawn類函數。
              在這一節里,我們還要講講system()和popen()函數。system()函數先調用fork(),然后再調用exec()來執行用戶的登錄shell,通過它來查找可執行文件的命令并分析參數,最后它么使用wait()函數族之一來等待子進程的結束。函數popen()和函數system()相似,不同的是它調用pipe()函數創建一個管道,通過它來完成程序的標準輸入和標準輸出。這兩個函數是為那些不太勤快的程序員設計的,在效率和安全方面都有相當的缺陷,在可能的情況下,應該盡量避免。
            Linux聯盟收集整理

            http://www.allegations.com.cn/baidu/8003/982.htm

            posted @ 2007-12-18 15:41 茶 閱讀(520) | 評論 (0)編輯 收藏

            unix多進程

                 摘要: 一.多進程程序的特點      由于UNIX系統是分時多用戶系統, CPU按時間片分配給各個用戶使用, 而在  實質上應該說CPU按時間片分配給各個進程使用, 每個進程都有自己的運行環境  以使得在CPU做進程切換時不會"忘記"該進程已計算了一半的"半成品". 以DOS  的概念...  閱讀全文

            posted @ 2007-12-18 13:35 茶 閱讀(456) | 評論 (0)編輯 收藏

            STL vector的使用

              http://www.cppreference.com/cppvector/index.html
            assign
            Syntax:
              #include <vector>
            void assign( size_type num, const TYPE& val );
            void assign( input_iterator start, input_iterator end );
            

            The assign() function either gives the current vector the values from start to end, or gives it num copies of val.

            This function will destroy the previous contents of the vector.

            For example, the following code uses assign() to put 10 copies of the integer 42 into a vector:

            vector<int> v;
             v
            .assign( 10, 42 );
             
            for( int i = 0; i < v.size(); i++ ) {
               cout
            << v[i] << " ";
             
            }
             cout
            << endl;            

            The above code displays the following output:

            42 42 42 42 42 42 42 42 42 42          

            The next example shows how assign() can be used to copy one vector to another:

            vector<int> v1;
             
            for( int i = 0; i < 10; i++ ) {
               v1
            .push_back( i );
             
            }              

             vector
            <int> v2;
             v2
            .assign( v1.begin(), v1.end() );            

             
            for( int i = 0; i < v2.size(); i++ ) {
               cout
            << v2[i] << " ";
             
            }
             cout
            << endl;            

            When run, the above code displays the following output:

            0 1 2 3 4 5 6 7 8 9     



            Vector constructors
            Syntax:
              #include <vector>
            vector();
            vector( const vector& c );
            vector( size_type num, const TYPE& val = TYPE() );
            vector( input_iterator start, input_iterator end );
            ~vector();
            

            The default vector constructor takes no arguments, creates a new instance of that vector.

            The second constructor is a default copy constructor that can be used to create a new vector that is a copy of the given vector c.

            The third constructor creates a vector with space for num objects. If val is specified, each of those objects will be given that value. For example, the following code creates a vector consisting of five copies of the integer 42:

            vector<int> v1( 5, 42 );         

            The last constructor creates a vector that is initialized to contain the elements between start and end. For example:

            // create a vector of random integers
             cout
            << "original vector: ";
             vector
            <int> v;
             
            for( int i = 0; i < 10; i++ ) {
               
            int num = (int) rand() % 10;
               cout
            << num << " ";
               v
            .push_back( num );
             
            }
             cout
            << endl;            

             
            // find the first element of v that is even
             vector
            <int>::iterator iter1 = v.begin();
             
            while( iter1 != v.end() && *iter1 % 2 != 0 ) {
               iter1
            ++;
             
            }              

             
            // find the last element of v that is even
             vector
            <int>::iterator iter2 = v.end();
             
            do {
               iter2
            --;
             
            } while( iter2 != v.begin() && *iter2 % 2 != 0 );              

             
            // only proceed if we find both numbers
             
            if( iter1 != v.end() && iter2 != v.begin() ) {
               cout
            << "first even number: " << *iter1 << ", last even number: " << *iter2 << endl;        

               cout
            << "new vector: ";
               vector
            <int> v2( iter1, iter2 );
               
            for( int i = 0; i < v2.size(); i++ ) {
                 cout
            << v2[i] << " ";
               
            }
               cout
            << endl;
             
            }

            When run, this code displays the following output:

            original vector: 1 9 7 9 2 7 2 1 9 8
             first even number
            : 2, last even number: 8
             
            new vector: 2 7 2 1 9          

            All of these constructors run in linear time except the first, which runs in constant time.

            The default destructor is called when the vector should be destroyed.

             

            posted @ 2007-12-11 14:26 茶 閱讀(4033) | 評論 (2)編輯 收藏

            網站記錄

            http://stl.winterxy.com/ 號稱最優秀的STL使用學習網站
            http://www.cppreference.com/ 英文STL使用資料參考網站
            http://www.uml.org.cn/oobject/Oobject-lt.asp  這玩意不通不行啊
            http://www.yesky.com/SoftChannel/72342371928702976/20031215/1753319.shtml com技術很nb的技術
            http://www.cnscn.org/

            http://www.jzxue.com/建站學

            http://www.bccn.net/Article/編程中國

            http://wenda.stx168.com/?site=yb 商問網

            http://topic.csdn.net/u/20081014/15/c69dd6c0-c0da-4ecf-a2c2-f0fa458bbc2a.html?seed=735903946
            失業七個月,面試六十家公司的深圳體驗

            posted @ 2007-12-11 14:02 茶 閱讀(261) | 評論 (0)編輯 收藏

            c++ STL 容器基礎(一)

                 摘要:   閱讀全文

            posted @ 2007-12-11 14:00 茶 閱讀(5599) | 評論 (2)編輯 收藏

            C++ STL編程入門基礎【簡摘】

                 摘要:   閱讀全文

            posted @ 2007-12-11 11:56 茶 閱讀(665) | 評論 (0)編輯 收藏

            僅列出標題
            共4頁: 1 2 3 4 
            亚洲国产精品久久久久婷婷老年| 久久久久国产精品人妻 | 亚洲午夜久久久久久噜噜噜| 欧美亚洲国产精品久久蜜芽| 国产精品99久久免费观看| 亚洲AV日韩精品久久久久久久| 国产精品久久久久久五月尺| 久久久午夜精品| 中文精品久久久久人妻不卡| 午夜不卡久久精品无码免费| 国产成人久久精品区一区二区| 97r久久精品国产99国产精| 久久亚洲精品视频| 国产一区二区精品久久凹凸| 色99久久久久高潮综合影院| 久久91精品国产91| AAA级久久久精品无码片| 久久综合九色综合97_久久久| 久久AⅤ人妻少妇嫩草影院| 亚洲国产综合久久天堂| 人妻无码久久一区二区三区免费| 国产精品无码久久久久久| 四虎国产精品免费久久5151| 亚洲AV伊人久久青青草原| 亚洲成色www久久网站夜月 | 亚洲国产精品嫩草影院久久| 亚洲av伊人久久综合密臀性色| 久久电影网一区| 日产精品久久久久久久| 成人综合伊人五月婷久久| 精品无码久久久久久久久久| 亚洲精品乱码久久久久久按摩 | 久久久SS麻豆欧美国产日韩| 97久久天天综合色天天综合色hd| 精品国产综合区久久久久久 | 亚洲精品乱码久久久久久蜜桃| 亚洲精品乱码久久久久66| 久久精品国产一区二区三区| 一本一本久久aa综合精品| 久久99精品免费一区二区| 久久国产欧美日韩精品|