在C++
中,system()函式是一個系統呼叫函式。函式的原型定義在stdlib.h/cstdlib
標頭檔案或者process.h
標頭檔案中。
process.h
這個標頭檔案並不是ISOC或者C++
標準的一部分,而是基於某些作業系統和特定編譯器的擴充套件,比如在Windows平臺上的MSVC(Microsoft Visual C++)編譯器。
該檔案主要用來進行程序控制。可以分為以下八個主要方向:
① 程序控制
abort(): 強制終止當前程序,併產生一個SIGABRT訊號。這通常會導致程序異常終止,並吐核。
exit(): 正常終止當前程序。
_exit(): 類似exit(),但是不呼叫任何清理處理程式,直接終止程序。常用在緊急情況下的快速退出。
② 獲取程序資訊
_getpid(): 獲取當前程序的ID。
_getppid(): 獲取當前程序的父程序ID。
③ 程序環境
getenv(const char *varname): 獲取環境變數的值。如果環境變數不存在,則返回NULL。
putenv(const char *envstring): 設定或者刪除環境變數。envstring的格式為varname=value,如果要刪除一個環境變數,可以將value設定為空字串。
④ 程序間通訊(IPC)
process.h標頭檔案本身不提供IPC的函式,但是與程序相關的IPC通常涉及到管道(pipes)、訊號(signals)、共享記憶體(shared memory)等機制。這些功能會在其他的標頭檔案中定義。
⑤ 執行緒屬性
_beginthreadex(): 建立一個新執行緒。這是建立執行緒的低階函式,提供了更多的控制。
_endthreadex(): 終止一個由_beginthreadex()建立的執行緒。
⑥ 執行和替換程序映像
_exec* 系列函式:這些函式用於替換當前程序的映像。
⑦ 建立新程序
spawn* 系列函式:這些函式用於建立一個新的程序來執行一個程式。
⑧ 系統命令執行
system)const char *command): 執行一個命令列字串。這個函式會建立一個子程序來執行命令,然後等待命令執行完成。
在process.h
標頭檔案中,system()
是這樣定義的。
#ifndef _CRT_SYSTEM_DEFINED #define _CRT_SYSTEM_DEFINED int __cdecl system(const char *_Command); #endif
當不存在對於_CRT_SYSTEM_DEFINED
的具體定義時,就定義該宏,並沒有給他分配任何特定的值,幷包含system函式的宣告。
在上述程式碼段中,出現了__cdecl這個關鍵字。這個關鍵字是指定函式呼叫約定的關鍵字之一。 呼叫約定指的是:在C和C++中,呼叫約定定義了函式引數如何被傳遞到函式,以及函式返回時誰負責清理呼叫棧。不同的呼叫約定可以影響函式的呼叫方式和效能。
__cdecl呼叫約定規定了以下幾個方面:
引數傳遞:引數從右到左被壓入堆疊;
堆疊清理:呼叫者(呼叫函式的程式碼)負責清理堆疊上的引數;
名稱修飾:在C語言中,函式名稱可能會被修飾(新增下劃線字首),比如
system
可能被轉換為_system
。
常見的呼叫約定還有:
__stdcall:在Windows API中廣泛使用,引數從右到左被壓入堆疊,但被呼叫者負責清理堆疊。
__fastcall:引數使用就差你其傳遞,以減少堆疊操作,提高效能。
thiscall:用於成員函式的呼叫,第一個引數是this指標,傳遞給函式的第一個引數之前。
最好不要嘗試顯式指定呼叫約定,它是編譯器和平臺特定的。 比如在GCC和Clang中,是使用__attribute__來指定呼叫約定:
#ifdef __GNUC__ __attribute__((cdecl)) void myFunction() { ; } #endif
在MSVC中,是直接使用呼叫約定關鍵字:
void __cdecl myFunction(){ ; }
編譯器的預設約定已經足夠高效,只有在與比較舊的C程式碼庫互動或者有特定的效能需求時,纔可能需要考慮呼叫約定。
該函式會呼叫作業系統。首先system函式接收一個字串,並將它作為要執行的命令傳遞給系統的命令列直譯器。在Windows上通常是cmd.exe,而在linux上通常是/bin/sh。 此外,在呼叫時system()
時,該操作會新建一個程序,因此會有一些效能上的問題。在執行完畢後,返回命令執行後的退出狀態。在Unix-like系統中返回值通常是命令的退出碼,在Windows系統中,如果成功執行,返回值通常是0。