re: 偶見CSDN的VC6的猛人 lymons 2010-05-05 11:18
@戰魂小筑
不得不說,事實確實如此。
使用VC6,微軟并不會查你,
不管你要錢,不就是不收費嘛。
#不要忘了,10年前的時候微軟的策略就是VC6有標價,
但不收費,你隨便用,目的不說你也清楚。
re: [原]深入講解函數中分配內存問題 lymons 2010-05-05 10:40
我覺得只要理解指針的概念就明白這是怎么回事兒了。
指針變量的內容,和指針指向的內容是兩碼事兒。
指針本身也是一個變量,它的內容存放的是它所指向空間的地址。
想要讓指針指向別的地方,就得把這個指針變量的內容賦值上
這個地方的地址即可。
函數在進棧的時候,實參變量的內容 會被原樣復制到函數棧上。
也就是說,指針傳到函數里是它指向內容的首地址,其他變量傳到函數里是它的值。在函數里改變參數的內容,只會影響棧上的變量的內容, 不會影響調用者傳進來的實參。
所以,在函數里改變指針指向空間的內容,是沒有問題的,因為你知道這個空間的地址。
要是改變指針指向的地址,也就是讓他指向別的地方,則只會改變棧上的那個指針所指向的地址,也就是改變的是存放在棧上的地址,而非調用者傳進來的實參。
因此,想要改變調用者的指針指向的地址,就得把調用者的指針的地址(指針本身也是一個變量,它也有地址)傳到函數里去。
要么把形參寫成二級指針(**),要么寫成指針地址(*&). 后者的方式C不支持。
re: 偶見CSDN的VC6的猛人 lymons 2010-05-05 09:46
話也不盡然,
任何事情的存在都它存在的道理。
不能因為高效的新工具的出現,就否定老工具存在的價值。
舉一個最簡單的例子,VC6存在的一個典型的理由:
VC6免費,VC2003以上價值不菲,對于一個遵紀守法的
中小軟件企業,在不需要高級應用的情況下,是不會批量購買
收費的版本的。
在公司眼里,時常要衡量的是提升效率所帶來的成本,是否能得到
相應的收益。
這不像個人使用,即使使用了盜版的開發工具,也不會有人查你,
商業公司則不一樣,如果使用了這些軟件,每天都有人盯著你。
re: 某內存池中的指針用法 lymons 2010-05-05 09:32
很棒,學習了。
不過,這對單個block的分配是個很好的解決方案,
但是要是分配多個block呢?
在重載delete操作符的函數中,是沒有辦法知道要本次要刪除的內存
到底有多少個塊,也就沒有辦法維護這些block中的地址表。當然,
除非把block數作為參數傳進去,但這樣的話,就造成了用戶
的麻煩,用戶在刪除分配給自己的內存的時候還必須記得這塊內存里
的block的數目,萬一寫錯了,后果不堪設想。
re: 設計模式-策略模式[未登錄] lymons 2010-04-30 20:51
@陳海濤
最瞧不上你這種人,動不動就說別人說的不對,總是以自己是高手自居.
你要說覺得對方寫的不對,你就把你的觀點寫出來,指出對方哪地方寫錯了.
這樣才能讓大家受教啊.
拜托啊.....請你回到正常人的行列來.
#我只是路過這里的路人甲,看到你的回復,實在是氣不過.抱歉....
如果大家對內存中的棧空間(stack)有足夠的了解的話,這道題就變的容易的多了。
首先bz給的答案是對的。
原理就是利用棧空間中的一個空閑位置來存儲我們的計算數據。
實際上就是把這個空閑位置當成一個臨時的存儲空間來用。
比如,你可以寫的更簡單一些。
int mystrlen(char *string)
{
*(long *)(&string - sizeof(char *) - 4) = (long)string;
while(*string++);
return ((long)string - *(long *)(&string - sizeof(char *) - 4) - 1);
}
寫法雖然不同,但原理都是完全一樣的。
>>>>這里跟我預期想的減兩個int大小有點出入,為什么減的是0x20?
這有兩個原因:
1。 棧空間永遠是從高地址向低地址的方向發展的
2。 編譯器至少給當前函數分配20h(32)個字節的棧空間,即使該函數里沒有一個局部變量
所以,ESP(棧頂指針)會向下減去20h個字節。這樣,這32個字節是給當前函數使用的,在bz的例子中,因為函數里沒有一個局部變量,所以,這32個字節都是可以任意讀寫訪問的。
只要您找到這個空閑空間的地址,你當然就可以往里面寫入自己的數據嘍。
只要明白上面的事情,代碼就容易編寫了。
&string 就是 形參string在棧空間中的地址,把這個地址減去一個sizeof(char *),這是因為,形參string下面放的是函數的返回地址(不是返回值哦),它是不能被修改的,否則就會被hack了。然后再減去4個字節,這個就是該函數的第一個空閑位置的地址了。
其實,了解棧的朋友都知道,當前正在被執行的函數永遠是處于棧頂的位置,所以棧頂下面的空間都是沒有人使用的,只要您不超過棧空間的范圍(棧空間大小的默認值好像是8MB,不過一般的編譯器都能設置這個值),你就可以訪問這里面的任何一個地址。如果你像下面那么寫,也沒有任何問題,編譯器也不會有任何抱怨,也能得到正確的值:
int mystrlen(char *string)
{
*(long *)(&string - sizeof(char *) - 400) = (long)string;
while(*string++);
return ((long)string - *(long *)(&string - sizeof(char *) - 400) - 1);
}
不過,你得注意的是減去的這個值必須是地址寬度(4個字節)的整數倍。
以上是俺的一點拙見,歡迎探討。
另外,糾正一下樓上幾位朋友的小錯誤。
棧空間里任何地址和內存都是靜態的,所以對于當前進程來說,他們都是可讀寫的,不存在非法訪問,所以才會出現緩沖區溢出的漏洞,會被那些hacker抓住,奪取系統的管理權限;
而堆里的內存如果在沒有被分配出來的情況下,才會出現非放訪問。如果您了解進程空間的布局,您就不會犯這個錯誤了。
re: Callback在C\C++中的實現 lymons 2010-04-21 10:27
我覺得這種做法是把簡單的問題復雜化了。
在決定使用 函數指針/回調函數 來作為我們的實現方案的時候,我們要考慮的事情是:
1. 由注冊函數的人來決定這個函數被調用時的參數。 還是,
2. 由這個函數的將來的調用者來決定該函數的參數。
如果是1, 則局限性比2要大,因為在注冊函數的時候,并不完全清楚在函數調用時的實際情況,所以在某些場合,提前設定好了參數,到了實際調用的場合,這些參數有可能不合適。
而2,完全是由調用者根據實際情況來決定用什么樣的參數來傳遞到調用函數中,靈活性更強。而這種場合,編碼實現也最簡單,無非就是一個函數指針而已。
而往往,函數的注冊者和函數的調用者幾乎都是一個人/用戶, 所以為何非要提前來決定這個函數的調用參數,而讓問題的實現變得更加復雜呢。
我認為這得不償失。而,在商業軟件開發中,很少會為了1的情況,而增加額外的測試,代碼檢視的成本。
可以參考linux內核的文件系統的實現。其中,VFS和實際文件系統之間的接口,就是利用了簡單的函數指針,代碼并不像1那么復雜。
@sun2bird
你的目的是在根節點的末尾添加一個子節點呢? 還是在根節點之后追加新節點?
我所知道的,一般情況下,xml只有一個根節點. 如果在根節點之后添入新節點的話,恐怕有問題,是吧.
re: Linux 進程互斥鎖 lymons 2008-12-25 10:43
flock就是用fcntl系統調用實現的。
因為在linux內核里fcntl就是按照advise模式來實現,所以他一直是一個建議鎖。
我建議你可以使用sys v的信號量,在Linux下這畢竟比posix的更常用一些。
如,使用semget(2)來創建信號量,利用semop(2)來做PV操作。
re: Linux 進程互斥鎖 lymons 2008-12-24 17:32
雖然沒有仔細看你寫的代碼,但從設計思路上也能看出一些端倪出來。
flock實現的文件鎖實際上是一個建議鎖。也就是意味著在這個鎖很容易
收到外界的干擾。如果用于鎖定的文件被某人/某進程刪除了,那使用
這個文件鎖的程序就很容易出現紊亂。這點也需要考慮。
從你man出來的信息來看
LinuxThreads currently does not support process-shared semaphores, thus sem_init always returns with error ENOSYS if pshared is not zero.
這說的應該指的是LinuxThread吧,指的不是進程。
sema設計的初衷就是為了讓進程間進行通信,信號量如果不能共享那也就不能進行通信是吧。所以,我認為你應該放心的去用sema。至少是目前版本的大多數的linux系統都沒有問題。這僅僅是俺一家之言,如有不對之處請斧正。
re: 使用 fork 所要注意的 lymons 2008-12-23 17:41
>>>>2:對于指針的拷貝,只拷貝指針的值,不拷貝指針所指向的內容(malloc 和 new 方式申請的內存)。
對于這點我不認同。
創建出來的子進程是要完全拷貝父進程的內存地址空間(內存印像),也就是子進程的內存和父進程的是一模一樣的,當然也包括在堆(heap)里存放的動態內存。
所以,除了指針之外,指針指向的內容也是要拷貝出來。
雖然你打印出來的p_malloc_指向的地址都是相同的,但這個地址是存在于在兩個不同的虛擬地址空間,而且內容是一模一樣的,但它們是兩塊不同的物理內存。所以打印出相同的地址,這并不能說明父子進程的指針是指向同一塊內存的。
另外,在子進程里對p_malloc_進行任意的讀寫都不會影響到父進程的這塊同樣的內存,反之,父進程來操作地址相同的內存也不會影響到子進程。
你可以在子進程的代碼里,在sleep(10);之后添加對p_malloc_進行讀寫的語句,看它能否正確執行。請你驗證一下。
bz里描述的問題是 關于list容器的size函數帶來的效率的問題,而不是
怎么提高讀寫效率的問題,大家不要跑題啊。
而且,在讀取的過程中,還要對超過固定行數之后的容器進行統計處理。
各位高手們,請仔細看bz的source的機能要求吧。
re: C中如何調用C++函數[未登錄] lymons 2007-12-01 14:58
這種方法 得修改要調用函數的C++的源代碼文件,在里面添加一個給C的接口函數才可以。
但是在大多數的C開發里,我們往往是看不到要調用的C++的代碼,
或者說對方只給你提供C++的庫的二進制代碼的時候,這個時候該怎么辦呢?
re: 去掉string里面的所有空格[未登錄] lymons 2007-11-30 12:42
@沐楓
關于效率問題,俺的想法是 看這段代碼放到哪里去運行,如果是在游戲,嵌入式系統等,或者成為系統性能瓶頸的時候,必須要考慮這段代碼的性能的問題。
如果就是在其他的商業軟件里,就不必要為這段代碼考慮效率的問題,而是要著重與開發工時一起權衡考慮。我們不會為了僅僅提高了系統0.0001%的性能而浪費0.1%的工時。當然,也不是完全不考慮效率的問題,而是在一定工時里寫出盡可能漂亮,盡可能高效的代碼。 這僅僅是我的一點拙見,有不對之處請斧正。
另外,我對把“優化工作完全交給編譯器來做”這個觀點不敢茍同。
寫的非常糟糕的代碼,編譯器的優化遠遠比不上用人把這段代碼重寫而優化的好。 完全靠編譯器來優化我認為有點不妥。
re: 去掉string里面的所有空格[未登錄] lymons 2007-11-30 11:56
@沐楓
程序里返回的并不是局部變量的指針,它返回的是傳入到函數里參數的地址。
所以,調用者拿到該返回值跟實參是一個東西。
在函數返回給調用者之前,實參的內容還沒有被銷毀。
re: 去掉string里面的所有空格[未登錄] lymons 2007-11-29 22:50
@沐楓
您這個最棒. 謝謝!
多謝各位熱心人的指點,俺是不勝感激.
PS 如果是考慮效率的話,我是認為用C來實現可能效率比string更高一些吧.