目前分類:C/C++ 程式設計 (73)
- Aug 08 Tue 2006 22:43
檢查字串練習 (字數計算)
- Aug 08 Tue 2006 22:35
判斷字串是否為utf8編碼
- Aug 07 Mon 2006 03:35
巨集的字串連結使用範例
- Jul 11 Tue 2006 23:46
C++ Traits Example Source Code
- Jun 10 Sat 2006 04:52
C++基本功:全面掌握const、volatile和mutable關鍵字
- Jun 10 Sat 2006 04:31
正確使用const / 關鍵字Const 與Volatile的使用
- May 02 Tue 2006 06:44
區域設置和忽略大小寫的字串比較
- Apr 09 Sun 2006 09:04
Starting interactive processes with QProcess
Starting interactive processes with QProcess
interactive file I/O in Qt 的處理機制 & POSIX dup(2) - Linux-specific 特性
I've been playing with QProcess quite a bit lately, which is a wonderful class. However, I noticed that I cannot start an interactive process with it (i.e. a process that gets stdin from the terminal). This is because QProcess redirects stdin for all processes it starts back to the parent process, so that the programmer can send data to the process using write(). Thing is, I don't want this. So, after talking a bit with Andreas (who wrote QProcess), we came up with the following trick:
class InteractiveProcess : public QProcess
{
static int stdinClone;
public:
InteractiveProcess(QObject *parent = 0)
: QProcess(parent)
{
if (stdinClone == -1)
stdinClone = ::dup(fileno(stdin));
}
protected:
void setupChildProcess()
{
::dup2(stdinClone, fileno(stdin));
}
};
int InteractiveProcess::stdinClone = -1;
- Mar 26 Sun 2006 07:59
通過mismatch或lexicographical比較 實作簡單的忽略大小寫字串比較
通過mismatch或lexicographical比較
實作簡單的忽略大小寫字串比較
一個STL菜鳥最常問的問題是「我怎麼使用STL來進行忽略大小寫
(這個問題一個比較難的版本也能用STL解決。另文說明 )為了讓簡單的問題
- Mar 23 Thu 2006 22:32
Converting a String to Upper Case
C++
Converting a String to Upper Case
I recently received an e-mail message suggesting a "simpler technique" for converting a string object to uppercase letters. This technique is allegedly simpler than the original solution I presented elsewhere. To make this discussion more interesting and edifying, I will not post my original solution yet. The reader's message is as follows (as usual, I omitted identification details):
- Feb 16 Thu 2006 23:48
cppunit 單元測試
- Feb 09 Thu 2006 00:54
C++進階用法
1.
#include <iostream.h>
void main()
{
int i=3,j=5;
if ((i=3)||(j=6)){
cout <<"i="<<i<<" j="<<j;}
}
Q: What is the output? i=?? j=??
解答1:
第一題的答案是 i=3 j=5,並不會執行 j=6 這個給定值,由於C++是左手邊優先(Left hand side),所以當OR( || )給值出現的時候,所出現的就是第一個成立就不再往下看。所以並不會執行到 j=6 自然而然 j=5
2.
#include <iostream.h>
class C1
{
public:
int i;
C1( ){ cout <<"1--------"<<endl;}
~C1( ){ cout <<"2--------"<<endl;}
};
class C2
{
public:
int i;
C2(){ cout <<"3--------"<<endl;}
~C2( ){cout <<"4--------"<<endl;
}
};
int fun1( )
{
static C2 aa;
C1( );
cout <<"test_function--------"<<endl;
}
void main()
{
int x=0;
C1 c;
C2 * v;
cout <<"test1--------"<<endl;
//*v=C2( );
v=&C2( );
cout <<"test2--------"<<endl;
fun1( );
v->i =111;
cout <<v->i<<endl;
}
Q: What is the output?
解答2:
1---------
test1-----
3---------
4---------
test2-----
3--------
1--------
2--------
test_function----------
2---------
4---------
在類別的建構者函數與解構者函數之中,會呼叫到建構者函數就是當物件成立的時候,所以當 C1 c; 的時候就會呼叫 C1 的建構者函數。但是 在建立類別指標的時候(物件指標)並不會呼叫建構者函數與解構者函數,反倒是在指向位址時所使用的 C2( ) 所代表的就是將『類別當成靜態函數來使用』這樣一來可以讓指標去指定該物件,但是由於是當成函數使用所以 C2的建構者函數與解構者函數都會一併執行。而在Scope方面,由於 Static 的Scope 是最大的,所以相對的解構者函數也會比較慢出現∼∼∼
*v=C2()與 v=&C2()的差異
差異如下:
基本上
int x=10;
int *v;
*v=x;
此時由於 v尚未給值, 所以 *v 給定x時,會發生不可預知的錯誤
所以一開始在初始化指標的時候,都應該給定一個位置
v=&x 才能將位址給v
而 *v 才能找到 x
而不是不可預知的位置
*v=x與 v=&x 是完全不同的
x, &x, v, *v, &v 這幾個的意義:
compile 後,
x 會有一個 int 大小的記憶體, 內容是 10, &x 是 x 的記憶體位址 (address)
v 是一個 pointer, 要指向一個 int 大小的記憶體位址,
&v 是 v 的記憶體位址, *v 是 v 所指向的那個記憶體位址的內容, int *v 後, 系統只給 v 一個 pointer 大小的記憶體, v 所指向的位址並沒有給..., 你沒有指定 v 指向某塊記憶體, 卻要更改這個 "某塊記憶體內容", int *v 讓 v = 一個未知的記憶體位址 (也許是系統 address 0x0000??), 也就是 v 指到一個未知的記憶體, 而你用 *v = x, 要強迫更改這個未知記憶體的內容, 你要把 address 0x0000?? 的內容變成 10, 當然是錯誤!!! 因為 address 0x0000?? 的位置並不是你的程式可以存取的地方.... 而 v = &x, 是指定 v 的內容為 x 的 address, 也就是 v 指向 x 這個己經被系統配置的記憶體位置, 它是真實被 x 宣告可使用的, *v = 5 這時所更改的, 也就是 x 的內容...
3.
Static i;
Global j;
Q: What is difference between i,j?? and what is difference between Static and Global??
解答3:
在Scope方面,大家都知道 Static 與 Global的用法,就是比起一般區域變數的Scope都還大,但是這兩個到底有什麼差距呢?原來,比起來Global比Static 更廣大的Scope,也就是 Static 代表該變數的 Scope範圍到『整個檔案』,但是 Global卻是橫跨數個檔案,皆可以呼叫Global的參數(只要使用 extern來呼叫即可∼∼∼)所以大家都會忘記,其實 Global的範圍才最大,但是記得使用外部檔案的變數還是要宣告一下。
4.
string s1("test1");
string s2("test2~~~");
string & rs=s1;
string * ps=&s1;
cout <<"rs1="<<&rs<<" ps1="<<*ps;
rs=s2; //Label 1
ps=&s2; //Label 2
cout <<"rs2="<<&rs<<" ps2="<<*ps;
Q: What is the output aboute between Label1 and Label2?
解答4:
這一題只要是在考『指標』(pointer)與『物件化身』(reference)兩者的差別,根據去查書『More Effective C++』裡面有提到,其實兩者用法很像,確有以下的不同
* Reference 沒有空值(NULL)存在
* Pointer 的位置可以變動而 Reference 則否
所以以上的題目中 rs =s2 是將 s1中的值改為 s2的數值,而 ps=&s2 則是將指標 ps 指向 s2而已罷了∼∼∼
- Feb 07 Tue 2006 23:21
C++ 語言相關探討,細究指標(pointer)與參照(reference)
- Jan 05 Thu 2006 19:29
STL & Iterators
The Mac OS, STL, & Iterators
by Duane Murphy, Bear River Associates, Inc.
Take advantage of the C++ Standard Library Algorithms with the Mac Toolbox
Iterating The Toolbox
There are many parts of the Mac OS Toolbox that require you to search for what you need. Search for files with a certain type code. Search for a process with a particular creator code. Search for mounted volumes that are removable. The list of managers in the Mac OS that require searching goes on and on. So, we write search and loop routines to do the work.
- Sep 28 Wed 2005 19:59
Newlib函式庫的優勢利用
Newlib 是一個用於嵌入式系統的開放源程式碼的C語言程序庫。特點是輕量級,速度快,可移植到很多CPU結構上。
Newlib函式庫是一個複雜的標準C 函式庫,包括字符串支持,浮點運算,內存分配(malloc),和I/O流函數(printf,fprinf(),等等)。Newlib有兩個組件構成:libc提供了主要的C 語言函式庫的實現,而libm提供了浮點運算支持。
為什麼要為Newlib費心呢?如果你正在寫一個非常小的嵌入式系統,你可能有自己的C標準函式庫的子集。但是如果你要求很多的基本函數,那麼一個現存的庫能夠幫你跳過大量的工作而使你集中力量在真正的任務上。這就是Newlib的價值,你可以從Newlib中的得到100,000多行的預先寫好的經過測試的函式庫程式碼。
儘管Newlib 提供了複雜的函數集,你不用擔心它脹滿你的ROM。程式碼是非常模塊化的,所以你的目標程式碼連接器將在需要的時候從庫中呼叫相應的功能。
發布與授權許可
Newlib函式庫的發布是源程式碼級的,你在嵌入式應用中使用它前需要交叉編譯生成二進制庫。由於主要使用GNU GCC交叉編譯器工具鏈,所以使用GCC配置和生成二進制庫是一個簡單的處理過程。你也可以使用非GCC工具,但需要更多的手工配置。
Newlib 包括了從各種資源中收集來的程式碼,多個免費軟件授權的分發也反映了其起源的多樣性。基本上它有一個嵌入式系統開發者所喜愛的像BSD一樣的非限制性授權。允許你不需要公開你的源程式碼來使用該庫。你可以從newlib home page 得到更詳細的信息。
系統呼叫例程
Newlib依賴於少量的系統呼叫例程,你必須對依賴於系統的任務提供處理,特別是I/O支持。例如,你呼叫了printf()函數,Newlib函式庫負責創建一個格式化的字符串,但是不知道在那裡或如何顯示它。因此它需要呼叫_write系統例程來執行最後輸出。
int _write(int handle, char *ptr, size_t len);
當呼叫printf()的時候,」handle」將被保留其中」1」意味著stdout標準輸出,」ptr」指向包含格式化字符串的緩衝區,」len」將是格式化字符串的長度。你的_write()系統呼叫例程的實現是通過一個串行調試端口發送緩衝區內容到一個遠端的調試終端上顯示出來。
下面是Newlib可能需要的系統呼叫例程的列表。不要被這個列表嚇住:很少需要你來實現所有這些呼叫。而且經常是返回-1來指示一個錯誤或者一個合適的偽結果。
* _sbrk: 改變堆的分配(對 malloc而言)
* _open: 打開文件(基於句柄的)
* _close: 關閉文件
* _write: 寫文件
* _read: 讀文件
* _lseek: 重新定向文件中的位置
* _fcntl: 執行一個文件描述符的操作
* _fstat: 得到文件狀態的句柄
* _stat: 按名稱得到文件狀態
* _link: 生成一個文件鏈接(文件命名)
* _unlink: 刪除目錄項
* _times: 讀取時間信息
* _gettimeofday: 得到時間日期
* _execve: 執行一個文件
* _kill: 殺死一個進程
* _getpid: 得到進程標識
* _fork: 創建一個新的進程
* _wait: 等待子進程的終止
實現系統呼叫例程的最簡單方法是按照需要來實現。直接使用Newlib函式庫,直到目標程式碼連接器警告一個庫函數缺少了一個系統呼叫函數再去實現它。通過這樣的方法,你就不會為那些你的系統不需要的系統呼叫浪費時間了。
接下來,我們來看一下 Newlib函式庫中的文件流I/O函數,並且討論在一個實時操作系統環境中使用Newlib函式庫的重進入和多線程問題。
在多線程環境中使用Newlib函式庫
Newlib提供了一個複雜的函數集,使用它們能夠讓你集中精力在真正的工作上。
我還提供了當使用newlib時需要實現的系統呼叫例程列表。現在,讓我們看一下Newlib函式庫中的文件流I/O函數,並且討論在一個多線程實時操作系統環境中如何安全使用newlib苦。
文件和I/O流支持
文件流I/O函數,例如fopen(), fread(), fwrite(), fprintf(), 和fclose(), 在Newlib函式庫中很容易被混淆。這裡有一個固有的文件系統嗎?沒有。在你所提供的基於句柄系統呼叫例程_open(), _read(), _write(), 和 _close()的頂部,這些newlib函數隻提供了緩衝區的流I/O層。
這裡的基本原理是你能夠像在UNIX/POSIX中對待文件那樣處理I/O設備。你的系統呼叫例程能夠將文件I/O請求定向到你想要的地方:串口,LCD顯示屏,塊存儲設備,文件系統驅動器等等。
如果你有多個設備,當你通過_open().打開一個設備時需要返回一個唯一的句柄。然後函數_read(), _write(), 和 _close()通過這個句柄參數決定將一個請求定向到哪一個設備上。
不要忽視這一工具,不要低估這種機制的力量。
在多線程環境中使用newlib
C的標準函式庫是天生沒有重進入點的。如果沒有顧慮的這一點,它將導致在多線程實時操作系統環境中的使用不安全。這是因為某些函數需要靜態數據來保持呼叫的狀態信息,而其他函數依賴errno靜態變量來報告錯誤程式碼。如果多線程中的函數呼叫修改了相同的靜態數據,將發生致命的混淆。
幸運的是,Newlib函式函式庫程式碼已經涵蓋了這一點。沒有在簡單的存儲位置存儲它的靜態變量,Newlib函式庫定義了 _reent結構封裝了庫中需要的所有靜態變量。一個單一的指針(_impure_ptr)指向了_reent數據塊。Newlib函式庫中的所有函數都使用了_impure_ptr 指向的_reent數據塊中的「靜態「數據。
這種機制的背後是這樣一種思想,在一個多線程環境中,每個任務必須由它自己的_reent數據塊。進一步,無論實時操作系統什麼時候執行一個任務切換,你必須為這個新激活的任務改變指向的_reent數據塊的_impure_ptr指針。
如果在一個多線程環境中運行Newlib函式庫,要注意兩點:
1. 為每一個任務分配一個_reent結構
2. 在實時操作系統上下文切換中,為這個新激活的任務改變指向的_reent數據塊的_impure_ptr指針
如果在你的實時操作系統裡有合適的系統呼叫,你通常很容易的實現這些(更容易的是你有實時操作系統的源程式碼)。
系統默認地為單線程環境保留一個的_impure_ptr指針指向的_reent結構實例。所以,如果你不運行多線程應用,你不用考慮這些問題。
當你寫嵌入式應用的程式碼時,你也不需要明白這種機制。例如,可以按照往常那樣修改標準C的errno變量,如下所示:
errno = 0;
但是在這種情形的背後,errno被一個宏定義實現成以下程式碼,所以每個人物猶他自己的私有errno變量。
_impure_ptr->errno = 0
保護newlib的堆管理器
在多線程環境中,使用malloc() 和free()函數可以保護對newlib所管理的系統堆的訪問。不要讓兩個以上的任務同時操縱堆。
在強調一下,newlib使在訪問對管理結構前後呼叫_malloc_lock() 和 _malloc_unlock()系統例程變得簡單,本著使用實時操作系統的互斥機制保證在同一時間只有同一任務訪問堆的原則,來實現_malloc_lock() 和 _malloc_unlock()就可以了。
不要跳過這一步。即使嵌入式應用中沒有明確的呼叫malloc(),Newlib函式庫內部有時也會自己使用malloc()。
- Jul 20 Wed 2005 01:17
Install STLport on MAC OSX procedure
- Jul 05 Tue 2005 09:14
MSN Passport Password竊取代碼