在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。