C語(yǔ)言中system()函數(shù)的用法總結(jié)
system()函數(shù)功能強(qiáng)大,很多人用卻對(duì)它的原理知之甚少先看linux版system函數(shù)的源碼:
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>
int system(const char * cmdstring)
{
pid_t pid;
int status;
if(cmdstring == NULL){
return (1);
}
if((pid = fork())<0){
status = -1;
}
else if(pid = 0){
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
-exit(127); //子進(jìn)程正常執(zhí)行則不會(huì)執(zhí)行此語(yǔ)句
}
else{
while(waitpid(pid, &status, 0) < 0){
if(errno != EINTER){
status = -1;
break;
}
}
}
return status;
}
分析一下原理估計(jì)就能看懂了:
當(dāng)system接受的命令為NULL時(shí)直接返回,否則fork出一個(gè)子進(jìn)程,因?yàn)閒ork在兩個(gè)進(jìn)程:父進(jìn)程和子進(jìn)程中都返回,這里要檢查返回的pid,fork在子進(jìn)程中返回0,在父進(jìn)程中返回子進(jìn)程的pid,父進(jìn)程使用waitpid等待子進(jìn)程結(jié)束,子進(jìn)程則是調(diào)用execl來(lái)啟動(dòng)一個(gè)程序代替自己,execl("/bin/sh", "sh", "-c", cmdstring, (char*)0)是調(diào)用shell,這個(gè)shell的路徑是/bin/sh,后面的字符串都是參數(shù),然后子進(jìn)程就變成了一個(gè)shell進(jìn)程,這個(gè)shell的參數(shù)是cmdstring,就是system接受的參數(shù)。在windows中的shell是command,想必大家很熟悉shell接受命令之后做的事了。
再解釋下fork的原理:當(dāng)一個(gè)進(jìn)程A調(diào)用fork時(shí),系統(tǒng)內(nèi)核創(chuàng)建一個(gè)新的進(jìn)程B,并將A的內(nèi)存映像復(fù)制到B的進(jìn)程空間中,因?yàn)锳和B是一樣的,那么他們?cè)趺粗雷约菏歉高M(jìn)程還是子進(jìn)程呢,看fork的返回值就知道,上面也說(shuō)了fork在子進(jìn)程中返回0,在父進(jìn)程中返回子進(jìn)程的pid。
windows中的情況也類(lèi)似,就是execl換了個(gè)又臭又長(zhǎng)的名字,參數(shù)名也換的看了讓人發(fā)暈的,我在MSDN中找到了原型,給大家看看:
HINSTANCE ShellExecute(
HWND hwnd,
LPCTSTR lpVerb,
LPCTSTR lpFile,
LPCTSTR lpParameters,
LPCTSTR lpDirectory,
INT nShowCmd
);
用法見(jiàn)下:
ShellExecute(NULL, "open", "c:\\a.reg", NULL, NULL, SW_SHOWNORMAL);
你也許會(huì)奇怪 ShellExecute中有個(gè)用來(lái)傳遞父進(jìn)程環(huán)境變量的參數(shù) lpDirectory,linux中的execl卻沒(méi)有,這是因?yàn)閑xecl是編譯器的函數(shù)(在一定程度上隱藏具體系統(tǒng)實(shí)現(xiàn)),在linux中它會(huì)接著產(chǎn)生一個(gè)linux系統(tǒng)的調(diào)用 execve, 原型見(jiàn)下:
int execve(const char * file,const char **argv,const char **envp);
看到這里就會(huì)明白為什么system()會(huì)接受父進(jìn)程的環(huán)境變量,但是用system改變環(huán)境變量后,system一返回主函數(shù)還是沒(méi)變。原因從system的實(shí)現(xiàn)可以看到,它是通過(guò)產(chǎn)生新進(jìn)程實(shí)現(xiàn)的,從我的分析中可以看到父進(jìn)程和子進(jìn)程間沒(méi)有進(jìn)程通信,子進(jìn)程自然改變不了父進(jìn)程的環(huán)境變量。
使用了system函數(shù)就能執(zhí)行dos指令。
#include <stdio.h>
#include <stdlib.h>
xiaoyu()
{
char *a;
int n=0;
FILE *f;
f=fopen("file.bat","w+");/*新建一個(gè)批處理*/
if(f==NULL)
exit(1);
a="echo"; /*DOS命令*/
for(n=65;n<=90;n++)/*大寫(xiě)A-Z*/
fprintf(f,"%s %c\n",a,n);/*利用ASCII碼輸出A-Z,寫(xiě)出批處理*/
fclose(f);
system("file.bat");/*運(yùn)行批處理*/
}
main()
{
char *string;
xiaoyu();
string="echo C語(yǔ)言的system函數(shù)\n";/*輸出中文*/
system(string);
system("pause");/*程序暫停*/
}
C中可以使用DOS命令,以后編程通過(guò)調(diào)用DOS命令很多操作就簡(jiǎn)單多了。
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)繪制南丁格爾玫瑰圖的示例代碼
玫瑰圖中有一種不等半徑的統(tǒng)計(jì)圖稱(chēng)為南丁格爾玫瑰圖,網(wǎng)上很熱門(mén),是一很有藝術(shù)感的漂亮的統(tǒng)計(jì)圖,下面我們就來(lái)看看如何使用C語(yǔ)言繪制它吧2024-03-03C 語(yǔ)言編寫(xiě)一個(gè)計(jì)算器界面(可視化界面和多功能)
今天給大家分享一個(gè)計(jì)算器功能,主要功能有加法減法乘除法求余功能,用戶(hù)可以在主菜單選擇需要計(jì)算的功能,接下來(lái)根據(jù)用戶(hù)輸入的數(shù)字進(jìn)行計(jì)算輸出結(jié)果,喜歡的朋友拿去用吧2021-06-06C++實(shí)現(xiàn)打印1到最大的n位數(shù)
這篇文章主要介紹了C++實(shí)現(xiàn)打印1到最大的n位數(shù),并分析了實(shí)現(xiàn)代碼中語(yǔ)句的跳轉(zhuǎn)技巧,需要的朋友可以參考下2014-09-09C語(yǔ)言用函數(shù)實(shí)現(xiàn)反彈球消磚塊
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言用函數(shù)實(shí)現(xiàn)反彈球消磚塊,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05C++實(shí)現(xiàn)職工工資管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)簡(jiǎn)單的職工工資管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03C++報(bào)錯(cuò) XX does not name a type;
這篇文章主要給大家介紹了C++報(bào)錯(cuò) XX does not name a type;field `XX’ has incomplete type解決方案,文中通過(guò)代碼示例講解的非常詳細(xì),需要的朋友可以參考下2023-08-08