程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 深入研究C語言 第二篇,深入研究c第二篇

深入研究C語言 第二篇,深入研究c第二篇

編輯:關於C語言

深入研究C語言 第二篇,深入研究c第二篇


1. 程序一:

首先我們研究如下程序:

回答如下問題:

1. 程序運行時n,a,b,c的段地址在哪個寄存器中?

全局變量的存儲空間在什麼段裡?局部變量的存儲空間在什麼段了?參數在什麼段裡?函數的返回值存儲在什麼地方?

全局變量的存儲空間在什麼時候分配?什麼時候釋放?

局部變量的存儲空間在什麼時候分配?什麼時候釋放?

2. 函數f3在調用與返回方式與函數f1與f2有何不同?

我們編譯完成後,進入debug查看。

首先,我們執行到main函數處,然後開始單步執行。我們看到,每次單步執行時,涉及到取數據或者數據賦值的操作,debug都會顯示出要操作的地址的地址和當前值。我們先來驗證這個地址和值是否是正確的:

由於源程序中賦值n為0,不好驗證是否正確,我們將n的賦值暫時改為n=10;我們驗證如下:

(語句執行後DS:01a6處的值)

(語句未執行前DS:01a6處的值)

可以看到,n=10這條語句執行時,debug右側顯示出要操作的地址為DS:01A6,而程序執行後,DS:01a6處的值變為了0A,也就是說,被賦值的n的地址就是這裡。由此,我們可以確定,debug單步執行時的地址和當前值是可信的。

我們依據每次單步執行時的debug值來確定每個變量的位置:

這裡,n=0;全局變量的地址為:DS:01A6,DS段值為0B96。

執行到此,我們看到的依然是全局變量n的地址。

繼續執行,我們進行到f2函數調用時。我們看到, f2(1,2);中的參數,2和1分別被壓入了棧中。並且其參數壓入的順序是從右向左壓入的。其段地址當然是SS。

在f2中參數被調用時,是用BP加偏移量的方式被調用。最後時,將結果給了AX。在這裡變量C就沒有再內存中賦值,而是直接用SI、AX來保存的過程值。而參數被調用的時候,用的段寄存器是SS。

另外在退出f2函數的過程中,我們看到:

在入棧是分別是AX(第二個參數)、AX(第一個參數)、BP、SI。而出棧是只將SI、BP出棧,並沒有將AX出棧。在這個時候,參數就被釋放掉了。

然後程序就返回了,所以我們在此處確定,函數返回值return是通過AX返回的。

將n賦值時,將變量AX的值賦值給了n。

這裡也是n的賦值。

我們在編寫這樣一個程序:

從這裡我們更清晰的看出局部變量是定義在棧段裡。而且,我們看到在函數一被調用時就有sub sp+02,所以我們可以看出,在程序調用的時候就分配下了變量的空間。

所以:程序運行時,n的段地址是DS,A的段地址是SS,B的段地址是SS,C沒有在數據段中,使用的是寄存器AX。

全局變量的存儲空間在數據段中,局部變量的存儲空間在棧段裡,參數的存儲空間在棧段裡,函數的返回值儲存在AX中。

全局變量的存儲空間在執行到聲明變量的語句時分配,程序結束後被釋放。

局部變量在函數被調用時分配,在函數結束後被釋放。

參數的存儲空間在調用函數時分配,在函數調用結束後釋放。

我們對比f1和f3調用的不同,發現:1.調用時,f1是call 偏移地址,而f3是call 段地址+偏移地址。2.返回時,f1是直接RET,f3是先RETF再RET。

2. 程序二:

我們編寫如下程序:

問題:變量n與a的存儲空間分配方式有何不同?

編譯完成後進入debug跟蹤。

我們看到,A在程序開始就被分配,A在偏移位置為0194的位置存放。而N則是PUSH進棧,這時候才在棧中分配的,在這之前是在SI中存放的。而且,C程序的編譯器對程序作了優化,將語句簡化。

我們做驗證:

編寫程序:

首先我們看到,C語言在實現的時候,並沒有按照我們在C語言中的語句順序這樣一條一條的翻譯,而在底層的實現方式是,將n=2與n++放在一起。且變量n放置在寄存器SI中。

3. 程序三:

我們編寫程序如下:

問題:

1. 程序中所有變量的存儲空間相鄰麼?tc2.0中,整型、字符型、長整數型數據的存儲空間分別為多大?

2. 不同的數據類型對數據運算方式有何影響?

Debug查看main函數執行時a、b、c、a1、a2的地址。

觀察知:a、b、c、a1、a2的地址分別為:0194、0196、0198、0199、019B。

我們看到他們之間的差值分別是:2、2、1、2。我們知道int型變量的大小是2字節,所以可以看到,這些變量是連續的。

而且我們還看到,在int和char行數據++的時候,都是用的inc指令,而long型的是用的ADD指令。說明不同類型的數據所對應的數據運算方法不同。

我們看到這裡,long型的變量,先用add,在用adc指令。這是因為long型變量長度是4字節,而匯編沒有四字節的加法。只能先將低兩位進行加法,然後再將有高兩位與溢出標志位進行加法(這裡是因為低兩位相加的時候有可能溢出,如果溢出,應該向高兩位進1,,而adc指令是帶溢出位進行運算的。這樣以來就可以保證高兩位的值是正確的)。這樣來完整的完成一次四字節的加法。

我們查詢TC的變量長度:

我們可以推測,a2後的變量的地址為019F。我們驗證:

這裡也說明不同類型的變量是連續的,也可以說明long占用了4個字節。

4. 程序四:

編寫程序如下:

問題:變量a,b和他們的各個數據項的存儲空間是如何分配的?

首先我們分析自定義數據類型:它是由一個int型,三個char型變量共同組成的。這樣一個數據類型應該再內存中占用5個字節。而兩個自定義數據類型的變量a、b,他們一個是全局變量,一個是局部變量。在分配時,應當一個在數據段中,一個在棧段中。

編譯完成後debug查看結構體內的變變量來進行驗證:

我們看到,在自定義的結構體stu類型的全局變量a中,其各個數據項的排列是連續的。且整個變量a都在數據段,所占用的長度為5個字節。

在在自定義的結構體stu類型的局部變量b中,其各個數據項的排列依然是連續的。且整個變量都在棧段裡,所占用的字節為5個。並且,在這裡我們發現,雖然是對棧段做操作,但是這裡沒有用PUSH指令,用的也是MOV指令。並且我們看到,在程序一開始的時候,

Sp就做了相應的修改,把b的空間分配出來了。

5. 程序五:

我們編寫如下函數,看結構體變量是如何傳遞和返回的:

反匯編如下:

我們看到,在匯編中有LEA這條指令,LEA就是目標地址傳送指令: 將一個近地址指針寫入到指定的寄存器。格式:LEA reg16,mem16。

在程序中,我們看到這這樣的調用,結合上下文我們可以確定是調用的func函數。我們看其反匯編的代碼:

我們看到,程序將0b28給了ax,但是我們知道,ax存放子函數返回值的寄存器。那麼ax中放的是自定義的數據類型的變量麼?顯而易見,ax是放不下5個字節的。那麼,又沒有可能是偏移地址呢?我們查看。

果然,在數據段中我們找到了自定義類型a的存放地址。也就是說,func函數返回自定義類型的變量是靠返回其在數據段中的偏移地址返回的。

我們查看f函數的語句,看到f函數的偏移地址為0256。

我們找到調用語句:

我們看到,F中是用棧傳入的結構體變量。

所以,我們可以知道,自定義數據類型的變量在函數中返回時,是靠返回其在數據段中的偏移地址返回的。而其當做參數被調用時是借助棧機制傳入函數的。


C語言深入學習

C學完之後,最好繼續學C++,因為C是結構化編程,而C++是面象對象編程的,而且現在都流行C++。
語言學好之後應該先學數據結構和算法,因為這是編程的靈魂,所以要必須學好,而且還要學精。
至於編譯原理,應該沒那個必要學習,如果你要搞破解軟件,可以學一下,編譯原理,主要就是研究,編譯器的工作原理的,也就是學習像VC這樣的編譯軟件,是怎樣對C語言進行什麼詞法分析,句法分析,和語法分析什麼的,這個對游戲開發應該沒有什麼用。
數據庫應該要學一點,因為編寫游戲程序同樣需要一大堆的數據,比如什麼游戲裡面的地圖數據,這些都是保存在一個文件中的,因此在編程的時候難免會和這些大規模的數據打交道,而處理大規模數據一般都是數據庫的事情,因此應該有必要了解一下。
對於操作系統,也應該學習一下,因為你開發的游戲,必竟要經過某一個操作系統來運行,因此應了解一下操作系統的原理,但重點應學好和windowAPI,因為游戲多半還是是和windows打交道的。
然後游戲開發就是樓上所說的OpenGL和DirectX也是很重要的內容,不過那是後面的事情了,也要學好。
 

c語言深入問題

我來講點你要聽的,
首先,語言只是工具。從這點出發不贊同改行學其他的語言。一門語言既然存在總有用武之地,學好了總有適合你做的。
然後數據結構和算法當然是要學的,你如果沒看過《算法導論》的話建議你看看。如果你學過了,你應該要了解一下你要從事什麼方面的編程?如果只是想寫點小程序練練手,那就比較好辦。你需要學習一些基礎理論知識,例如網絡,編解碼之類的。你要做什麼你就去學習相關的東西。然後你要學習軟件工程,開發軟件要遵循一些套路,不能毫無章法地亂寫一通。
總的來說你自己學,自己寫小程序的話你應該是需要什麼學什麼。因為知識的連通性很強,學科交叉性也很強,計算機的應用必然涉及到各個方面,不可能只學一門編程語言就完事的。
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved