C 主回路没有';我不能正常退出
我创建了此功能,作为基于终端的应用程序的主菜单:C 主回路没有';我不能正常退出,c,terminal,atexit,C,Terminal,Atexit,我创建了此功能,作为基于终端的应用程序的主菜单: bool wizard_run() { char *command = NULL; bool repeat = false; bookmark: terminal_prepare(); terminal_message(MESSAGE_INTRODUCTION); loop: /* repeat until a valid command */ { free(command); /* free
bool wizard_run() {
char *command = NULL;
bool repeat = false;
bookmark:
terminal_prepare();
terminal_message(MESSAGE_INTRODUCTION);
loop: /* repeat until a valid command */ {
free(command); /* free any previous command */
command = terminal_command(PROMPT_COMMAND, COMMAND_LENGTH, repeat);
if (!strcmp(command, COMMAND_ENCRYPT)) wizard_encrypt();
else if (!strcmp(command, COMMAND_DECRYPT)) wizard_decrypt();
else if (!strcmp(command, COMMAND_CONCEAL)) wizard_conceal();
else if (!strcmp(command, COMMAND_REVEAL)) wizard_reveal();
else if (!strcmp(command, COMMAND_ERASE)) wizard_erase();
else if (!strcmp(command, COMMAND_GENERATE)) wizard_generate();
else if (!strcmp(command, COMMAND_NAVIGATE)) directory_navigate(RDS_HOME)
else if (!strcmp(command, COMMAND_SESSION)) wizard_session();
else if (!strcmp(command, COMMAND_SAFEMODE)) wizard_safemode();
else if (!strcmp(command, COMMAND_HELP)) wizard_help(HELP_MAINMENU)
else if (!strcmp(command, COMMAND_EXIT)) {free(command); return false;}
else {repeat = true; goto loop;}
}
free(command); /* free last command */
return true;
}
void main() {
// initialize any Components needed
if (!directory_rdsload()) return;
packager_reset();
// show the Splash Screen
SPLASH();
// continuously execute the Main Thread
while (wizard_run()); /* execution loop */
// perform any Clean-UP needed before exit
reset();
encryption_reset();
directory_reset(is_safemode);
}
所有大写值都是#定义的
常量,所有…(…)
都是函数,除了向导帮助(…)
和目录导航(…)
都是宏(这就是为什么这些行后面没有分号的原因)
这是应用程序的主要功能:
bool wizard_run() {
char *command = NULL;
bool repeat = false;
bookmark:
terminal_prepare();
terminal_message(MESSAGE_INTRODUCTION);
loop: /* repeat until a valid command */ {
free(command); /* free any previous command */
command = terminal_command(PROMPT_COMMAND, COMMAND_LENGTH, repeat);
if (!strcmp(command, COMMAND_ENCRYPT)) wizard_encrypt();
else if (!strcmp(command, COMMAND_DECRYPT)) wizard_decrypt();
else if (!strcmp(command, COMMAND_CONCEAL)) wizard_conceal();
else if (!strcmp(command, COMMAND_REVEAL)) wizard_reveal();
else if (!strcmp(command, COMMAND_ERASE)) wizard_erase();
else if (!strcmp(command, COMMAND_GENERATE)) wizard_generate();
else if (!strcmp(command, COMMAND_NAVIGATE)) directory_navigate(RDS_HOME)
else if (!strcmp(command, COMMAND_SESSION)) wizard_session();
else if (!strcmp(command, COMMAND_SAFEMODE)) wizard_safemode();
else if (!strcmp(command, COMMAND_HELP)) wizard_help(HELP_MAINMENU)
else if (!strcmp(command, COMMAND_EXIT)) {free(command); return false;}
else {repeat = true; goto loop;}
}
free(command); /* free last command */
return true;
}
void main() {
// initialize any Components needed
if (!directory_rdsload()) return;
packager_reset();
// show the Splash Screen
SPLASH();
// continuously execute the Main Thread
while (wizard_run()); /* execution loop */
// perform any Clean-UP needed before exit
reset();
encryption_reset();
directory_reset(is_safemode);
}
这里,只有SPLASH()
是宏
所有布尔值(即true
,false
)都是预定义的无符号字符值,bool
是typedef无符号字符bool代码>
它的正常行为是在用户输入exit
(命令的当前值)时退出向导运行()
循环,执行reset();加密重置();目录重置(是安全模式)代码>然后正常终止应用程序。相反,当我第一次键入exit
时,它会重新显示菜单,当我第二次键入exit
时,它会终止,并出现以下错误:
application: cxa_atexit.c:99: __new_exitfn: Assertion `l != ((void *)0)' failed.
Aborted (core dumped)
当程序在gdb
下运行时,我得到以下错误:
application: cxa_atexit.c:99: __new_exitfn: Assertion `l != ((void *)0)' failed.
Program received signal SIGABRT, Aborted.
0xb7fdd424 in __kernel_vsyscall ()
除了main()
之外,没有其他函数调用wizard\u run()
,因此这不是菜单重新显示而不是退出的原因。有什么想法吗
提前谢谢!!!:好的,我终于找到问题了!它位于SPLASH()
中。这是一个宏,定义为:
#define SPLASH() { \
if (!vfork()) execlp("/bin/splash", "/bin/splash", NULL); \
else wait(); \
}
由于我的应用程序仍处于测试阶段,我没有将splash
放入目录/bin
。我从没想过这会是个问题。然而,这里有一个陷阱:我使用vfork
而不是fork
,因为我只想执行一个新程序(vfork
在不需要子进程作为父进程副本时更快)。由于不存在/bin/bash
,execlp没有为子进程加载新的应用程序映像。因此,我可以想象这两个进程共享了它们的一部分图像?()
因此,当调用SPLASH()
时,子进程将接管并再次显示主菜单。一切看起来都很好。但当我调用退出时,子菜单会正常终止,父菜单控制终端并重新显示主菜单(这就是为什么它会显示两次!)。当再次调用exit
时,轮到父进程终止。但是,与父进程共享同一进程映像的子进程已经终止,从而改变了一些数据。一定是这些修改过的数据导致了退出时的错误
当我的功能清除终端并写入以前的消息时,我没有注意到子进程首先显示主菜单!;)
我对整个问题的性质感到非常兴奋。虽然我无法更好地解释它(我一定是在我的术语中犯了一些错误),但我希望你理解哪里出了问题!感谢大家的宝贵意见(尤其是WhozCraig)!!:D在调试器下运行此操作,当该断言触发时,我几乎可以保证您将得到一个堆栈跟踪,确切地说明发生这种情况的原因。您有太多我们看不到代码的函数调用(terminal\u command()
将是一个非常可疑的函数调用)。另请注意:wizard\u run()
中的goto
是完全不需要的;清除它并使用适当的while
-loop.Functionterminal_command()
使用printf
和scanf
打印提示消息并读取用户输入(命令)。最后一个布尔值确定是覆盖终端中的上一个提示还是转到新行。我要做的是启动应用程序并立即键入exit
。显示的错误转储看起来是因为exit handler函数链在不应该被覆盖时被覆盖。如果在程序中没有任何其他障碍的情况下发生这种情况,请首先在主程序中注释while循环到wizard\u run()
。如果这个“有效”,那么把它带回来并注释掉循环中的所有垃圾,直到只剩下退出逻辑。。一次一块地添加,直到它重新生成。我相信您或您使用的代码正在以未定义的行为方式写入内存,并且与所有未定义的行为一样,很难找到它。如果您的命令阅读器非常简单,请发布它。如果它不是问题的根源,那就顺其自然吧,但这里有大量函数,其中任何一个都可能导致问题,我们都看不到问题的代码。如果没有明确的代码,你将得到最好的猜测,但没有具体的。