PC中最主要的難題之一,也是最容易引起誤解的,就是系統(tǒng)調(diào)用。系統(tǒng)調(diào)用所代表的那些函數(shù)實(shí)際上是計(jì)算機(jī)的所有底層操作——屏幕和磁盤(pán)的控制,鍵盤(pán)和鼠標(biāo)的控制,文件系統(tǒng)的管理,時(shí)間,打印,這些只不過(guò)是系統(tǒng)調(diào)用所實(shí)現(xiàn)的一部分功能。
總的來(lái)說(shuō),系統(tǒng)調(diào)用往往涉及到BIOS(基本輸入輸出系統(tǒng))。實(shí)際中有好幾種不同的BIOS,例如主板的BIOS負(fù)責(zé)初始硬件檢測(cè)和系統(tǒng)引導(dǎo),VGA BIOS(如果有VGA卡的話)處理所有的屏幕處理函數(shù),固定磁盤(pán)BIOS管理硬盤(pán)驅(qū)動(dòng)器,等等。DOS是位于這些低級(jí)BIOS之上的一個(gè)軟件層,并且提供了進(jìn)入這些低級(jí)BIOS的基本接口。一般說(shuō)來(lái),這意味著有一個(gè)DOS系統(tǒng)調(diào)用可以調(diào)用幾乎所有你想使用的系統(tǒng)功能。實(shí)際上,DOS將調(diào)用相應(yīng)的一種低級(jí)BIOS來(lái)完成所要求的任務(wù)。在本章中,你將會(huì)發(fā)現(xiàn)你既可以調(diào)用DOS來(lái)完成一項(xiàng)任務(wù),也可以直接調(diào)用低級(jí)BIOS來(lái)完成相同的任務(wù)。
14.1 怎樣檢索環(huán)境變量(environment variables)的值?
ANSI C標(biāo)準(zhǔn)提供了一個(gè)名為getenv()的函數(shù)來(lái)完成這項(xiàng)任務(wù)。getenv()函數(shù)很簡(jiǎn)單一把指向要查找的環(huán)境串的指針傳遞給它,它就返回一個(gè)指向該變量值的指針。下面的程序說(shuō)明了如何從C中獲得環(huán)境變量PATH的值:
# include
main(int argc, char * * argv)
{
char envValue[l29]; / * buffer to store PATH * /
char * envPtr = envValue ; / * pointer to this buffer * /
envPtr = getenv("PATH"); /* get the PATH */
printf ("PATH= %s\n" , envPtr) ; / * print the PATH * /
}
如果你編譯并運(yùn)行了這個(gè)程序,你就會(huì)看到與在DOS提示符下輸入PATH命令完全相同的結(jié)果。事實(shí)上,你可以用getenv()檢索AUTOEXEC.BAT文件中的或者系統(tǒng)引導(dǎo)后在DOS揭示符下輸入的所有環(huán)境變量的值。
這里有一個(gè)小技巧。當(dāng)運(yùn)行Windows時(shí),Windows設(shè)置了一個(gè)名為WINDIR的新的環(huán)境變量,它包含了Windows目錄的路徑全名。下面這段簡(jiǎn)單的程序用來(lái)檢索這個(gè)串:
# include
main(int argc, char * * argv)
{
char envValue[l29];
char * envPtr = envValue ;
envPtr = getenv("windir");
/ * print the Windows directory * /
printf("The Windows Directory is %s\n" , envPtr);
}
這個(gè)程序還可以用來(lái)判斷當(dāng)前是否正在運(yùn)行Windows,以及DOS程序是否運(yùn)行在一個(gè)DOS shell下,而不是運(yùn)行在“真正的"DOS下。注意,程序中的windir字符串是小寫(xiě)——這一點(diǎn)很重要,因?yàn)樗鼘?duì)大小寫(xiě)是敏感的。如果你使用WINDIR,getenv()就會(huì)返回一個(gè)NULL串(表示變量未找到錯(cuò)誤)。
用一putenv()函數(shù)也可以設(shè)置環(huán)境變量。但要注意,該函數(shù)不是一個(gè)ANSI標(biāo)準(zhǔn)函數(shù),在某些編譯程序中它可能不以這個(gè)名字出現(xiàn),或者根本就不存在。你可以用一putenv()函數(shù)做許多事情。實(shí)際上,在上面那個(gè)例子中,Windows正是用這個(gè)函數(shù)創(chuàng)建了windir環(huán)境變量。
請(qǐng)參:
14.2 怎樣在程序中調(diào)用DOS函數(shù)?
14.3 怎樣在程序中調(diào)用BIOS函數(shù)?
14.2 怎樣在程序中調(diào)用DOS函數(shù)?
其實(shí),當(dāng)調(diào)用printf(),fopen(),fclose(),名字以一dos開(kāi)始的函數(shù)以及很多其它函數(shù)時(shí),都將調(diào)用DOS函數(shù)。Microsoft和Borland還提供了一對(duì)名為int86()和int86x()的函數(shù),使你不僅可以調(diào)用DOS函數(shù),還可以調(diào)用其它低級(jí)函數(shù)。用這些函數(shù)可以跳過(guò)標(biāo)準(zhǔn)的C函數(shù)而直接調(diào)用DOS函數(shù),這常??梢怨?jié)省你的時(shí)間。下面的例子說(shuō)明了如何通過(guò)調(diào)用DOS函數(shù),而不是getch()和printf()函數(shù),從鍵盤(pán)上得到一個(gè)字符并將其打印出來(lái)(該程序需要在大存儲(chǔ)模式下編譯)。
# include
# include
char GetAKey(void);
void OutputString(char * );
main(int argc, char * * argv)
{
char str[l28];
union REGS regs;
int ch;
/ * copy argument string; if none, use "Hello World" * /
strcpy(str, (argv[1]== NULL ? "Hello World": argv[1])),
while ((ch = GetAKey()) ! =27){
OutputString(str);
}
}
char
GetAKeyO
{
union REGS regs;
regs.h. ah = 1; /* function 1 is "get keyboard character" * /
int86(0x21, ®s, ®s);
return( (char)regs. h. al) ;
}
void
OutputString(char * string)
{
union REGS regs;
struct SREGS segregs;
/ * terminate string for DOS function * /
* (string + strlen(string)) = ’$’;
regs.h. ah = 9; / * function 9 is "print a string" * /
regs.x. dx = FP_OFF(string) ;
segregs. ds= FP_SEG(string) ;
int86x(0x21, ®s, ®s, &segregs);
}
上例創(chuàng)建了兩個(gè)函數(shù)來(lái)代替getch()和printf(),它們是GetAKey()和OutputString()。實(shí)際上,函數(shù)GetAKey()與標(biāo)準(zhǔn)c函數(shù)getche()更為相似,因?yàn)樗cgetche()一樣,都把鍵入的字符打印在屏幕上。這兩個(gè)函數(shù)中分別通過(guò)int86()(在GetAKey()中)和int86x()(在OutputString()中)調(diào)用DOS函數(shù)來(lái)完成所要求的任務(wù)。
總的來(lái)說(shuō),系統(tǒng)調(diào)用往往涉及到BIOS(基本輸入輸出系統(tǒng))。實(shí)際中有好幾種不同的BIOS,例如主板的BIOS負(fù)責(zé)初始硬件檢測(cè)和系統(tǒng)引導(dǎo),VGA BIOS(如果有VGA卡的話)處理所有的屏幕處理函數(shù),固定磁盤(pán)BIOS管理硬盤(pán)驅(qū)動(dòng)器,等等。DOS是位于這些低級(jí)BIOS之上的一個(gè)軟件層,并且提供了進(jìn)入這些低級(jí)BIOS的基本接口。一般說(shuō)來(lái),這意味著有一個(gè)DOS系統(tǒng)調(diào)用可以調(diào)用幾乎所有你想使用的系統(tǒng)功能。實(shí)際上,DOS將調(diào)用相應(yīng)的一種低級(jí)BIOS來(lái)完成所要求的任務(wù)。在本章中,你將會(huì)發(fā)現(xiàn)你既可以調(diào)用DOS來(lái)完成一項(xiàng)任務(wù),也可以直接調(diào)用低級(jí)BIOS來(lái)完成相同的任務(wù)。
14.1 怎樣檢索環(huán)境變量(environment variables)的值?
ANSI C標(biāo)準(zhǔn)提供了一個(gè)名為getenv()的函數(shù)來(lái)完成這項(xiàng)任務(wù)。getenv()函數(shù)很簡(jiǎn)單一把指向要查找的環(huán)境串的指針傳遞給它,它就返回一個(gè)指向該變量值的指針。下面的程序說(shuō)明了如何從C中獲得環(huán)境變量PATH的值:
# include
main(int argc, char * * argv)
{
char envValue[l29]; / * buffer to store PATH * /
char * envPtr = envValue ; / * pointer to this buffer * /
envPtr = getenv("PATH"); /* get the PATH */
printf ("PATH= %s\n" , envPtr) ; / * print the PATH * /
}
如果你編譯并運(yùn)行了這個(gè)程序,你就會(huì)看到與在DOS提示符下輸入PATH命令完全相同的結(jié)果。事實(shí)上,你可以用getenv()檢索AUTOEXEC.BAT文件中的或者系統(tǒng)引導(dǎo)后在DOS揭示符下輸入的所有環(huán)境變量的值。
這里有一個(gè)小技巧。當(dāng)運(yùn)行Windows時(shí),Windows設(shè)置了一個(gè)名為WINDIR的新的環(huán)境變量,它包含了Windows目錄的路徑全名。下面這段簡(jiǎn)單的程序用來(lái)檢索這個(gè)串:
# include
main(int argc, char * * argv)
{
char envValue[l29];
char * envPtr = envValue ;
envPtr = getenv("windir");
/ * print the Windows directory * /
printf("The Windows Directory is %s\n" , envPtr);
}
這個(gè)程序還可以用來(lái)判斷當(dāng)前是否正在運(yùn)行Windows,以及DOS程序是否運(yùn)行在一個(gè)DOS shell下,而不是運(yùn)行在“真正的"DOS下。注意,程序中的windir字符串是小寫(xiě)——這一點(diǎn)很重要,因?yàn)樗鼘?duì)大小寫(xiě)是敏感的。如果你使用WINDIR,getenv()就會(huì)返回一個(gè)NULL串(表示變量未找到錯(cuò)誤)。
用一putenv()函數(shù)也可以設(shè)置環(huán)境變量。但要注意,該函數(shù)不是一個(gè)ANSI標(biāo)準(zhǔn)函數(shù),在某些編譯程序中它可能不以這個(gè)名字出現(xiàn),或者根本就不存在。你可以用一putenv()函數(shù)做許多事情。實(shí)際上,在上面那個(gè)例子中,Windows正是用這個(gè)函數(shù)創(chuàng)建了windir環(huán)境變量。
請(qǐng)參:
14.2 怎樣在程序中調(diào)用DOS函數(shù)?
14.3 怎樣在程序中調(diào)用BIOS函數(shù)?
14.2 怎樣在程序中調(diào)用DOS函數(shù)?
其實(shí),當(dāng)調(diào)用printf(),fopen(),fclose(),名字以一dos開(kāi)始的函數(shù)以及很多其它函數(shù)時(shí),都將調(diào)用DOS函數(shù)。Microsoft和Borland還提供了一對(duì)名為int86()和int86x()的函數(shù),使你不僅可以調(diào)用DOS函數(shù),還可以調(diào)用其它低級(jí)函數(shù)。用這些函數(shù)可以跳過(guò)標(biāo)準(zhǔn)的C函數(shù)而直接調(diào)用DOS函數(shù),這常??梢怨?jié)省你的時(shí)間。下面的例子說(shuō)明了如何通過(guò)調(diào)用DOS函數(shù),而不是getch()和printf()函數(shù),從鍵盤(pán)上得到一個(gè)字符并將其打印出來(lái)(該程序需要在大存儲(chǔ)模式下編譯)。
# include
# include
char GetAKey(void);
void OutputString(char * );
main(int argc, char * * argv)
{
char str[l28];
union REGS regs;
int ch;
/ * copy argument string; if none, use "Hello World" * /
strcpy(str, (argv[1]== NULL ? "Hello World": argv[1])),
while ((ch = GetAKey()) ! =27){
OutputString(str);
}
}
char
GetAKeyO
{
union REGS regs;
regs.h. ah = 1; /* function 1 is "get keyboard character" * /
int86(0x21, ®s, ®s);
return( (char)regs. h. al) ;
}
void
OutputString(char * string)
{
union REGS regs;
struct SREGS segregs;
/ * terminate string for DOS function * /
* (string + strlen(string)) = ’$’;
regs.h. ah = 9; / * function 9 is "print a string" * /
regs.x. dx = FP_OFF(string) ;
segregs. ds= FP_SEG(string) ;
int86x(0x21, ®s, ®s, &segregs);
}
上例創(chuàng)建了兩個(gè)函數(shù)來(lái)代替getch()和printf(),它們是GetAKey()和OutputString()。實(shí)際上,函數(shù)GetAKey()與標(biāo)準(zhǔn)c函數(shù)getche()更為相似,因?yàn)樗cgetche()一樣,都把鍵入的字符打印在屏幕上。這兩個(gè)函數(shù)中分別通過(guò)int86()(在GetAKey()中)和int86x()(在OutputString()中)調(diào)用DOS函數(shù)來(lái)完成所要求的任務(wù)。