----------------解决方案--------------------------------------------------------
不好意思,我在18楼的回复是错误的。睡了一觉醒来终于把问题看清了
我发现使用vc或c-free等32位编译器不可以实现,但是tc这种16位DOS系统下的编译器却可以,这是和操作系统有关的,不同的操作系统下的编译器提供的system()函数有不同的实现,下面分别讨论:
windows 在windows这种多任务分时操作系统中有进程的概念,用windows下的编译器编译楼主的代码生成的程序在运行时就成为一个进程,当调用这个版本的system()函数时main函数位于父进程中会阻塞暂停,system()会生成一个子进程完成系统调用,父进程将自己的当前目录写入环境变量中可以传递给子进程,但是子进程只能修改自己的环境变量,返回父进程后子进程的修改不会对父进程造成任何影响,类似我们函数调用中的传值调用。子进程结束后父进程继续运行,下面分析几次system调用:
//假设编译好的可执行程序的路径为d:/dir/test.exe
system(" c:"); //创建一个子进程,子进程的当前目录和父进程相同,然后子进程改自己的当前目录为c:
//结束一个子进程,返回父进程继续执行,父进程的当前目录(环境变量)不会被子进程改变,仍旧为程序所在目录d:/dir
system("cd \\");//创建一个子进程,子进程的当前目录和父进程相同,然后子进程改自己的当前目录为d:
//结束一个子进程,返回父进程继续执行,父进程的当前目录(环境变量)仍旧为程序所在目录d:/dir
system("dir");//创建一个子进程,子进程的当前目录和父进程相同,然后子进程显示目录d:/dir中的内容
这就是为什么最后显示的不是c:的内容,不同的人运行结果不一样的原因(看你把可执行程序放在哪个目录运行)
DOS DOS是一个单任务的操作系统,没有父进程和子进程的概念,在tc的函数库中system()函数是另一种实现,不会出现子进程不能修改父进程的当前目录(环境变量)的情况,这样三次system调用才可以配合起来使用。19楼的实现了功能就是因为他的编译器是tc内核的。我对DOS系统不了解,不能像上面一样具体分析几次system调用的过程,希望大家可以补充。
就写到这,如有错误欢迎大家讨论。
----------------解决方案--------------------------------------------------------
对 就是这个
我也不是很懂 不过用可以用chdir来解决这个问题
怎么解决啊??
----------------解决方案--------------------------------------------------------
22楼的兄弟我真的好佩服你啊 看了半天就是看不懂啊 我真的好苯啊!!~~~~~~~~
----------------解决方案--------------------------------------------------------
22楼的话如果没有错,可以加精哦。
----------------解决方案--------------------------------------------------------
咱们的编译器不一样啊 愁人啊
我用DEV-C++是对的得嘛..
----------------解决方案--------------------------------------------------------
TO 楼上
我用gcc编译试了下,运行结果和我分析的结果一样,不能显示上次system调用指定的目录。
你的DEV-C++是gcc移植到win中的版本,估计也不行,除非你把编译后生成的可执行程序放到了c盘根目录中,还有一种可能是DEV-C++用了tc的库函数 ,提供的system()函数和tc的一样。
建议你检查下编译后生成的可执行程序的目录,程序显示的目录,看看二者的关系,想想你说的对的什么意思。
----------------解决方案--------------------------------------------------------
system详细分析
system()函数功能强大,很多人用却对它的原理知之甚少,也就有了上面那么多的回帖,我想大家如果知道了system的具体实现就不会对楼主程序在很多编译器中不能表现自己希望的功能感到费解了。我对linux中的实现比较了解,具体分析这个,windows中的类似就不详解了。好了,先看linux版system函数的源码:
#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); //子进程正常执行则不会执行此语句
}
else{
while(waitpid(pid, &status, 0) < 0){
if(errno != EINTER){
status = -1;
break;
}
}
}
return status;
}
先分析一下原理,然后再看上面的代码大家估计就能看懂了:
当system接受的命令为NULL时直接返回,否则fork出一个子进程,因为fork在两个进程:父进程和子进程中都返回,这里要检查返回的pid,fork在子进程中返回0,在父进程中返回子进程的pid,父进程使用waitpid等待子进程结束,子进程则是调用execl来启动一个程序代替自己,execl("/bin/sh", "sh", "-c", cmdstring, (char*)0)是调用shell,这个shell的路径是/bin/sh,后面的字符串都是参数,然后子进程就变成了一个shell进程,这个shell的参数
是cmdstring,就是system接受的参数。在windows中的shell是command,想必大家很熟悉shell接受命令之后做的事了。
如果上面的你没有看懂,那我再解释下fork的原理:当一个进程A调用fork时,系统内核创建一个新的进程B,并将A的内存映像复制到B的进程空间中,因为A和B是一样的,那么他们怎么知道自己是父进程还是子进程呢,看fork的返回值就知道,上面也说了fork在子进程中返回0,在父进程中返回子进程的pid。
windows中的情况也类似,就是execl换了个又臭又长的名字,参数名也换的看了让人发晕的,我在MSDN中找到了原型,给大家看看:
HINSTANCE ShellExecute(
HWND hwnd,
LPCTSTR lpVerb,
LPCTSTR lpFile,
LPCTSTR lpParameters,
LPCTSTR lpDirectory,
INT nShowCmd
);
用法见下:
ShellExecute(NULL, "open", "c:\\a.reg", NULL, NULL, SW_SHOWNORMAL);
你也许会奇怪 ShellExecute中有个用来传递父进程环境变量的参数 lpDirectory,linux中的 execl却没有,这是因为execl是编译器的函数(在一定程度上隐藏具体系统实现),在linux中它会接着产生一个linux系统的调用 execve, 原型见下:
int execve(const char * file,const char **argv,const char **envp);
看到这里你就会明白为什么system()会接受父进程的环境变量,但是用system改变环境变量后,system一返回主函数还是没变,这就是我在22楼反复强调的。原因从system的实现可以看到,它是通过产生新进程实现的,从我的分析中可以看到父进程和子进程间没有进程通信,子进程自然改变不了父进程的环境变量。希望小菜们不要拿tc或使用tc库的其他编译器中的system的调用结果来反驳我,这不是一个概念,DOS早死翘翘了,玩linux吧。就说到这里了。
我在bc-cn混了这么久威望精华还都是0,今天写到手抽筋,没功劳也有苦劳,没苦劳还有疲劳,版主给我加个精,要不我以后还是去水区灌水算了
申请加精!
火狐发的怎么这么乱,现在用ie重新排版好看了点
[此贴子已经被作者于2007-5-29 1:35:38编辑过]
----------------解决方案--------------------------------------------------------