① 如何C語言與匯編混編
c語言可以嵌套匯編:
按照TC2.0的幫助系統所以說的,在TC2.0下是可以用匯編的,方法是使用asm關鍵字:其格式是:
asm opcode <operands> <;newline>,如同別的注釋一樣,<>之間的表示可選的;例如:
main()
{
char *c="hello,world/n/r$";
asm mov ah,9;asm mov dx,c;asm int 33;
printf("You sucessed!/n");
}
或者是:
main()
{
char *c="hello,world/n/r$";
asm mov ah,9
asm mov dx,c
asm int 33
printf("You sucessed!");
}
兩種格式其實是一種.如果你用的是第一種的樣式,記住:
每一句匯編語句都要以asm開頭,如果一行內有多個句子,
那麼千萬不要忘記在兩個句子之間的這個semicolon(分號),
但是最後一句匯編後面(如果後面沒有其它的語句)的分號可有可無,象第一個例子中的
asm int 33;後面的分號就可以不要,因為它的後面沒有其它
的語句了.但如果是這樣:
asm mov ah,9; asm mov dx,c;asm int 33; printf("You sucessed!");
那麼asm int 33;後面的分號便還是留下好,以免出現編譯錯誤!
在這一點上頗象C語言.
還有一種格式是
asm{ assembly language statement},這種格式應該被普遍的歡迎.
它們的例子如下(其中的語句排列格式與上面兩種相同):
asm{
mov ax,var1
add ax,var2
......
}
但是要注意這種格式TC2.0是不支持的!
只有後來的TC++3.0及後來的IDE支持!
工具的使用:
一旦你的C源文件里包括了這些好東西,則必須用TCC.EXE的COMMAND-LINE來編譯,具體的命令參數TCC.EXE已經提供,這里不復闡述了.最簡單的是:TCC C源文件名(使用這個方法,TCC會自動調用TASM.EXE和TLINK.EXE,並且能夠使TLINK.EXE正確的找到需要的.obj和.lib文件,如果你單步編譯的話,可能會碰到很多的問題,主要是TLINK.EXE它自己並不會去找.obj和.lib文件,你自己可以建一個.bat文件,如果要指定.lib文件的目錄的話可以用/L參數,在文章的後面有一個例子).但大家要注意了,看一下你的TC目錄下面到底是否有TASM.EXE文件,並在TURBOC.CFG(這個文件包括TCC.EXE運行期參數,這裡面所有參數在運很期都將被自動TCC.EXE使用,例如:-IH:/TC/INCLUDE/
-LH:/TC/LIB/)文件中設置好一些參數,並確認TASM.EXE的版本號要2.0以上,以及是否能夠向下兼容.但是在大多數的情況下TC的目錄是沒有TASM.EXE的,或是版本不正常.
如果你有TASM.EXE文件並且TURBOC.CFG文件也已經寫好了,但是還要注意一個
問題:運行TCC.EXE時要在獨立的DOS SHELL下面(不要害怕,這不是一個新東西,我的意思
是,不在諸如TC下的DOS SHELL下面運行,我曾經敗在這個問題下,當我發現時直想揍電腦
一頓,還好沒有,不然就沒有這篇文件了.)
還有一句重要的話:TC2.0支持大部分8086指令(當然用法有一些約定,不過現在我並不打算
進行詳細說明,因為那是一件很繁雜的事,以後有時間或許會寫出來----如果大家需要的話).
如果說上面我所說的那些約定很繁雜的話,那麼下面的方法該是多麼簡單啊!
讓我們使用Borland為TC2.0內建的變數來進行偽匯編.
或許你還不知道在TC2.0中還有一些內建的pseudo寄存器(可以看作是register 型的變數,但是它們比register型的變數好用的多)
_AX,_AH,_AL,
_BX,_BH,_BL,
_CX,_CH,_CL,
_DX,_DH,_DL,
_DI,_SI,_SP,
_CS,_DS,_ES,_SS
注意這些寄存器的size,_AX,_BX,_CX,_DX,_CS,_DS,_ES,_SS,_SI,_DI,_SP等都是16位的寄存器相當於C語言的unsigned int類型,其餘的都是8位的寄存器(相當於unsigned char)(TC怎麼可能支持32位的寄存呢,所以EAX等是不能用的,FS,GS和IP寄存器都是無效的),還有就是在傳遞參數的時候千萬不要忘記使用強制類型轉換.
中斷調用指令是:__int__(interrupt_#)(注意int的前輟和後輟都是兩個underscores)
For example:
#include<dos.h>
unsigned int _stklen=0x200;
unsigned int _heaplen=0;
main()
{
_DX=(unsigned int)"Hello,world./r/n$";
_AX=0x900;
__int__(0x21);
}
dos.h它是包含__int__()內建中斷調用語句的頭文件,因此是不可
缺少的._stklen和_heaplen是定義運行期堆棧和堆大小的兩個內部
引用變數(這是個我自己想的名詞,意指如果這兩個變數在源文件中
顯式的聲明了,那麼編譯程序會自會引用來構造編譯時期的信息以產生
用戶希望的目標文件,如果不顯式的聲明則編譯程序自動確定).
這兩個變數也有一些約定,如果_stklen不顯式聲明,_heaplen賦值為零
都表示棧和堆都是defult的.
最後在TC2.0中還有一個沒有說明的標志位寄存器flags,它也是內建
pseudo寄存器是:_FLAGS,是一個16位寄存器.這些內建的寄存器都可以進行
運算,但是要注意它們所代表的類型(必要時進行類型轉換);
看起來這是不是一種好的辦法啊(而且使用這種方法只要用個一個dos.h頭文件就好,
不需要用TCC編譯,可以直接在TC20的IDE下編譯).
TC2.0中也提供了一些簡單好用的函數來實現對DOS功能的調用如:
int86(...),int86x(...)(但是這些方法實際仍然要調用函數,所以不如使用
偽寄存器,又因為要牽涉到union REGS結構的內存分配所以系統的開銷是增大了,
而使用偽寄存器是最簡潔的),埠通信函數如:inportb(...),inport(...),
outportb(...),outport(...),指針轉換函數:FP_OFF,FP_SEG,MK_FP,這些函數在
幫助系統中都有,有用時大家可以查閱.
tlinkbat.bat的例子:
rem The lib environment variable is the directory of the .obj and .lib file
set lib=h:/tc/lib/
rem 這下面的句子中的c0s(C 零S)是一個.OBJ文件,是一個C程序的STARTUP文件
tlink %lib%c0s %1,%1,%1,/L%lib%emu.lib %lib%maths.lib %lib%cs.lib
set lib=
(使用時可將以rem開頭的句子刪除)
___________________________________________________
一些約定:
我們先說一下在TC20下寫匯編(內聯匯編--自己起的名字,大家可以想叫什麼叫什麼)時的編譯器的編譯原則:
1.所有在main()函數外的的匯編語言的語句都作為數據聲明語句處理,也即在編譯器編譯時會將它放在數據段中,如:
asm string1 db "Hello",,,'world!',0ah,0xd,"$"
main()
{
asm mov dx,offset string1
asm mov ah,9
asm int 33
asm mov dx,offset string2
asm int 33
}
asm string2 db "the string can be declared after the main() function!$"
象這些樣子在main()外面的匯編語言的數據定義語句(事實上不管是什麼匯編語句,
只要是在main()之外,包括這個句子:asm mov ax,0x4c00),在編譯後都放在數據段中,而C語言的數據聲明語句仍按C的規則!
2.所有在main()函內的匯編語言的語句在編譯後都放在代碼段中,包括這個句子:
asm string2 db "the string can be declared after the main() function!$"
3.不要在以asm 開頭的語句中使用C語言的關鍵字,這會導致編譯階段的錯誤
那麼,根據這三條大家會得到什麼樣的結論呢?(先閉上眼想一想,你可能會由此變的
很贊賞自己,是的你應該這樣相信自己是對的!)
讓我們一起看一下這個結論:
1.根據編譯原則1得到:不可以在main()外面寫匯編命令語句(不要笑,正是與C語言相同才值得注意!),在任何地方都不要進行任何的段定義和宏定義(這是因為編譯後的形式決定的,也即:在TC20下所有的匯編格式的語句只能是,直接性的數據定義和語句指令)!
2根據編譯原則2得到:不可以在main()之內使用匯編的語句進行數據定義(同樣不要笑,
大多數人在第一次在TC20下寫匯編都會有這樣的錯誤的)
3.如同類強制類型這樣的事是不可以在以asm開頭的匯編語句中使用的
好了,天即朗,氣瞬清!這樣一說,一個大體的框架就出來了!只要遵守這個原則寫,就可避免很多莫名其妙的錯誤出現!
通俗的說:
匯編語句的數據定義放在main()外面,指令放在main()裡面.
如果你沒有更好的文檔,那麼記住我的這些話!
一些細節的問題:
在以asm開頭的內聯匯編語句中是不支持C的轉義字元的,但是用C語言聲明一個字元數組(含有轉義字元的),然後用int 33 ah=9這功能時輸出這個字元串時,其中的轉義字元是有效的(這主要是因為編譯後其內部表示形式不同造成的,自己想想會有答案的).
內聯匯編支持C的一些如數值表示,字元串聲明格式等,
如:一個十六進制的數據可以用兩種方式表示:0xa 和0ah,字元串可以是這樣:
"Hello,world!$"(如同C)也可以這樣'Hello,world!$'(用匯編自己的方式).
象C一樣你同樣要注意賦值的類型,而且要比C更嚴格(匯編從來不自己動手做
如同類型轉換啊這樣事),所以一切的事完全要你自己做好!而且你不要企圖以C的形式
做這件事,如這樣的格式 asm mov dx,(unsigned)a(a是一個這樣的東西,
char a[ ]="hello,world!";),而且這樣句子也會導致錯誤:asm mov dx,word ptr a(邏輯錯誤),不過這不是在編譯時的錯誤,而是運行期的錯誤(具體的原因自己想一想,象word label這樣的東西的運算作用和會導致的後果),你可以這樣用一個句子做"中間人"如int i=(unsigned)a;asm mov dx,i(也千萬不要用asm mov dx,(unsigned)a 這樣的句子.但是,告訴大家一個好消息,你可以用指針指向一個字元串,然後你會驚訝你竟然可以這樣:
char *p="hello,world";asm mov dx,p,然後用int 33 ah=9的功能輸出這個字元串而不會有錯誤(這也表現出指針的特點,它是一個二位元組的(TC20下)變數,含有的是一個地址,這與其指向的變數的類型是毫無關系的).
內匯匯編語句不支持->這個運算符.還有標號的問題,在最後的例子中你會年看到一些特別之處!
上面所說的只是很細小並微少的一些事(也是很常遇到的),尚有很多的細節要說,但由於本人時間有限不能一一列舉,如C的結構在內聯匯編的應用等大家可以按照其運行機理去想想一下用法;另外,由於這只是一件學習的事,所以還是大家自己學(找一下有關文檔,當然現在已經沒有什麼比較完整的了),情況會好的多,我在對內聯匯編的學習過程中領會到了不少的東西,例如編譯原理方面的知識,以及如何做會使代碼更高效,占空間最少等的方法.最後向大家推薦一種方法,在利用TCC的-S開關可以生成C源文件的匯編代碼
(或許很多的人都用過)是很好的學習材料!祝大家學有所成!
Cstarter
02-11-17
/* 由於個人的時間和能力有限,難免有錯誤和不詳細的地方,請大家見諒!
My Email:[email protected] [email protected] QQ:170594633 */
一些例子:
下面這個例子是對沈美明 溫冬嬋的
<<IBM-PC 匯編語言程序設計>>清華版第十一章程序的改寫
可直接在命令行上鍵入 tcc filename 就可以,當然你要有TASM.EXE
/*
asm mus_frep dw 330,294,262,294,3 p(330)
asm dw 3 p(294),330,392,392
asm dw 330,294,262,294,4 p(330)
asm dw 294,294,330,294,262,-1
asm mus_time dw 6 p(25),50
asm dw 2 p (25,25,50)
asm dw 12 p(25),100
*/
asm mus_frep dw 330,392,330,294,330,392,330,294,330
asm dw 330,392,330,294,262,294,330,392,294
asm dw 262,262,220,196,196,220,262,294,330,262
asm dw -1
asm mus_time dw 3 p (50),25,25,50,25,25,100
asm dw 2 p (50,50,25,25),100
asm dw 3 p (50,25,25),100
main()
{
asm jmp start
/*設置發聲的頻率,這一段在沈美明 溫冬嬋的
<<IBM-PC 匯編語言程序設計>>清華版第十一章有詳細的說明 */
sound:
asm mov al,0b6h
asm out 43h,al
asm mov dx,12h
asm mov ax,533h*896
asm div di
asm out 42h, al
asm mov al,ah
/* 這個延時是用來防止兩次IO操作的最後一次操作的錯誤,
因為CPU比匯流排的速度快很多,所以 要延時等待第一次操作完成後再進行第二次操作*/
asm mov cx,1000
delay:
asm loop delay
asm out 42h,al
asm in al,61h
asm mov ah,al
asm or al,3
asm out 61h,al
/* 使用中斷15H功能86H延時CX:DX=微秒數*/
asm mov ax,2710h
asm mul bx
asm mov cx,dx
asm mov dx,ax
asm mov ah,86h
asm int 15h /*可用__int__(0x15);代替*/
asm mov al,ah
asm out 61h,al
asm jmp add_count
/*------------------*/
start:
asm mov si,offset mus_frep
asm lea bp,mus_time
frep:
asm mov di,[si]
asm cmp di,-1
asm je end_mus
asm mov bx,[bp]
asm jmp sound
add_count: /*標號不能用匯編語言寫*/
asm add si,2
asm add bp,2
asm jmp frep
end_mus:;
}
對於上面的程序大家可用偽寄存器的方法寫一個,要容易的多!
/*一個發聲程序!(引自<<PC技術內幕>>電力版--這個版不好,不如清華版的)*/
#include"dos.h"
main()
{
static union REGS ourregs;
outportb(0x43,0xb6);
outportb(0x42,0xee);
outportb(0x42,0);
outportb(0x61,(inportb(0x61)|0x03));
ourregs.h.ah=0x86;
ourregs.x.cx=0x001e;
ourregs.x.dx=0x8480;
int86(0x15,&ourregs,&ourregs);
outportb(0x61,(inportb(0x61)&0xfc));
}
② 在TC2.0上寫好程序怎麼保存編譯,連接
保存按F2
編譯是ALT+C裡面的第一個
連接時ALT+C裡面的第二個
運行是ALT+R的第一個,看結果是ALT+F5
③ 怎麼把C語言文件轉換成EXE文件啊
要先編譯才行的,記住計算機暫時只能讀懂機器語言,所有的高級語言也需要編譯後才能執行,當然C也不會例外,C語言只要用編譯器Compile之後就會出現EXE文件了。
④ 用tc2.0如何編譯程序
選中.c文件右擊打開方式選擇你安裝tc2.0的目錄然後選擇tc2.0.exe進去後按F10可以進入上面的菜單,在Compile菜單下點擊make exe file在點擊Run菜單下的run,另外需注意tc下要輸出必須在最後加上 getch()();
⑤ C語言程序設計找錯
相信你用的是TC20:
1.這個程序中b,c是整型,因為TC20是16位模式,int型存儲空間只有2位元組,無符號最大才65535,你那個計算出來的值太大,所以就錯了,把int b,c;改為long b,c;,printf中改為"%ld"就好了.樓上說的tc30是32位模式,int型是4位元組,和原來的long長度一樣,所以沒問題
2.同上
3.這個也是TC20的BUG,你需要手動連接浮點庫,在程序main開始加以下的語句:
float arg,*point=arg;
其中arg,point只要不和其他變數名重合就可以了
-------------------------------------
非要解釋清楚的話是這樣的:首先大的方面還是我說的那個,具體操作的時候是受自動類型轉換的影響,c=a/10000; 這個式子中a/10000的結果是9,就像你說的"在不超出整型的范圍內,長整型是可以付值給整型數據的",下面b=(a-c*10000)/1000; 這句中由於c和10000都在整型範圍,所以按整型計算,c*10000不等於90000,而是取低位,值為24464,這樣(a-24464)/1000就有了74這個結果了.
第二條是同樣的原理,90000和98765都被解釋為長整型常量,相減就沒問題,而9和10000都被解釋為整型常量,結果就出問題了
你可以試試改為這樣的式子b=(a-c*10000l)/1000;在10000後面加小寫的L,表示10000是長整型常量,按自動類型轉換結果也成了長整型,b的結果也就對了
⑥ 怎樣用TC20運行程序
多數軟體都可以使用下面的規律:
. 一般各項功能都可以在菜單裡面找到,比如編譯為EXE文件,以及運行此文件,這些操作都有相應的菜單項目。而菜單項目的後面有提示快捷鍵,對於經常需要做的操作,你會不知不覺的就記得了快捷鍵,無需死記硬背。
⑦ 在TC中,怎樣用命令編譯lib庫
定義函數庫的方法及應用:
一、2個相關的命令
1、TCC——TC的DOS下的命令行編譯連接工具
2、TLIB——TC的DOS下的庫操作工具
二、1個自定義的函數庫的例子
1、
在TC集成環境下,編一個文件USERADD.C
#define
_NO_MAIN
int
add(int
*a,int
*b)
{
int
c;
c=(*a)+(*b);
return
c;
}
按ALT—F9編譯
生成一個
USERADD.OBJ文件。
2、按F10—F—O
退到DOSSHELL(DOS環境下)
COPY
USERADD.OBJ
到
..\LIB目錄,在\LIB目錄下執行
TLIB
USERLIB.LIB+USERADD.OBJ
就生成了一個自己的函數庫
USERLIB,在這個函數庫里就包含了函數模塊
int
add(int
*a,int
*b)
的二進制代碼。現在已經將自定義的函數放進了函數庫,就可以把原文件USERADD.C刪掉不要了。(當然,為了以後維護方便,還是作一個備份為好)。
以後如有其它的函數模塊,也可以編譯後用TLIB
命令加入到這個函數庫里。
3、寫一個包含文件
USER1.H,寫完後COPY到INCLUDE
目錄。內容如下:
int
add(int
*,int
*);
4、作好了以上的自定義函數庫的准備工作,現在就可以使用了。
寫一個程序,取名為ADD-1.C,在程序中調用庫函數add(
);
#include
#include
void
main(
)
{
int
a,b,c;
a=20;b=30;
c=add(&a,&b);
printf(「%d」,c);
}
5、在DOS命令行下,執行
TCC
ADD-1.C
..\LIB\USERLIB.LIB
就OK!
運行ADD-1.EXE,可以看到輸出結果
50
Tc生成lib的方法:
擴展庫與自建LIB庫使用擴展庫TC所帶的庫在有的情況下是無法滿足功能要求的,自己寫一個太麻煩,找到了一個LIB庫又怕不會用。在WIN-TC中,對於使用外部的擴展庫(第三方LIB)提供了一個方便的解決方法:首先要確定你的LIB庫是FOR
TC版本的而不是FOR
VC或是其它的。如果確定是FOR
TC的版本的話就把你的首標文件(或稱頭文件),就是擴展名為*.h的文件拷貝到WIN-TC的include目錄里,然後把相應名稱的*.lib文件拷貝到lib目錄,然後再運行WIN-TC時選擇「編譯配置」菜單項,你會看到擴展庫信息欄目里有你的LIB庫文件名在上面了,但是沒有打鉤。然後你把它鉤選後再「確定」保存,以後的編譯程序時就自動鏈接該擴展庫了。自建立LIB庫將自己的代碼編譯成LIB庫的格式有利與保護自己的代碼版權。如何來生成自己的LIB庫呢?請按照下面的方法:
STEP
1——生成目標代碼(OBJ)
建立mylib的代碼文件/*********************
mylib.c
*********************/void
myfun(){printf("
myfun()
in
mylib.lib
");}然後保存為WIN-TC目錄下的mylib.c文件然後到菜單項:運行->編譯設置
看看「產生
OBJ
文件」是否已選擇,若未選擇則選擇之。然後回到主界面,點「編譯鏈接」按鈕(F9
⑧ 在TC20中, int i=65536; printf("%d\n",i);的輸出結果是
lz是想實驗
short
i=65536;printf("%d\n,i);吧
是的話輸出結果是0
我看了下反匯編的結果,給你解釋下為什麼是0吧
65536對應的16進制數十10000h,
short
i=65536經過匯編之後的結果是
mov
[i],10000h
i只佔16位對應10000h的低16位,最高位的1由於存不下了就自動舍棄掉了,所以i的值為0
不知道其他編譯器是不是也是這么處理的,我估計應該差不多,
忘說了,我的ide是vs2010
⑨ 如何把C語言文件轉換成EXE文件
C語言文件是指.c類型的文件(源文件)嗎?
在編譯器中找一下「編譯」(Compile)或「生成」(Build)等命令,一般快捷鍵是F5,即可在源文件旁Debug文件夾中生成一個同名的.exe應用程序。生成的話一般在生成後會運行該程序。
⑩ 我剛下了個tc編輯器不會用,誰能告示我怎麼用
Turbo C
Turbo C是Borland公司的產品,早期最經典的C語言編譯器,TC 2.0倍受程序員的青睞。
新版本有TurboC++3.0
Turbo C的優點是 體積小---小於5兆,功能還全,適合教學。
不足是 Dos界面,TC 2.0還不支持滑鼠,受界面所限編輯功能不好。
下面是它的安裝以及使用:
下載後,用Winzip解壓縮,用默認的目錄即是c:\unzipped\tc20,不過一般你不想將程序放在unzipped目錄下吧,即使放在這里,你也會發現它不好使.可能會出現某某文件找不到的錯誤.不要緊,這里有幾個解決方案:
一,什麼都不要動,把tc20目錄改為tc後,放到c盤跟目錄下只要tc目錄裡面的文件不壞,應該就能正常運行.
二,如果你不想將它放到c盤跟目錄下,也行.比如你放到了d:\turboc\目錄下.步驟:
打開tc的IDE編輯界面,選options菜單,打開後,選directories子菜單.現在你將會看到幾個路徑:
Include Directories, Library Directories, Output Directories,Source Directories四項
看一看你的tc目錄的路徑,裡面有include目錄和lib目錄.將這兩個目錄的完整路徑分別寫上,哈哈這下行了吧.
以下是正規的c語言安裝方式,適用於有安裝文件的tc用。
Turbo C 2.0的安裝非常簡單, 只要將1#盤插入A驅動器中, 在DOS的"A>" 下鍵入:
A>INSTALL
即可, 此時屏幕上顯示三種選擇:
1. 在硬碟上創造一個新目錄來安裝整個Turbo C 2.0系統。
2. 對Turbo C 1.5更新版本。
這樣的安裝將保留原來對選擇項、顏色和編輯功能鍵的設置。
3. 為只有兩個軟盤而無硬碟的系統安裝Turbo C 2.0。
這里假定按第一種選擇進行安裝, 只要在安裝過程中按對盤號的提示, 順序插
入各個軟盤, 就可以順利地進行安裝, 安裝完畢將在C盤根目錄下建立一個TC 子目
錄, TC下還建立了兩個了目錄LIB和INCLUDE, LIB子目錄中存放庫文件, &127;INCLUDE
子目錄中存放所有頭文件。
運行Turbo C 2.0時, 只要在TC 子目錄下鍵入TC並回車即可進入Turbo C 2. 0
集成開發環境。