我正在试图找出一种方法来摆脱for在该循环中调用的函数内的循环.我知道有可能让函数返回一个值,然后检查一个特定的值然后中断,但我想直接从函数内部执行.这是因为我使用内部库来处理特定的硬件,要求我的函数的函数签名如下所示:
void foo (int passV, int aVal, long bVal)
Run Code Online (Sandbox Code Playgroud)
我知道不使用返回值是非常糟糕的做法,但是有很多情况迫使我这样做,所以请耐心等待.
考虑以下示例:
#include <stdio.h>
void foo (int a) {
printf("a: %d", a);
break;
}
int main(void) {
for (int i = 0; i <= 100; i++) {
foo(i);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
现在这不编译.相反,我得到一个编译错误如下:
prog.c:在函数'foo'中:prog.c:6:2:错误:break语句不在循环或switch break中;
我知道这意味着什么(编译器说中断foo()不在for循环中)
现在,我可以从关于break语句的标准中找到的是:
break语句使控制权传递给最内部封闭while,do,for或switch语句之后的语句.语法只是简单;
考虑到我的函数是从for循环中调用的,为什么break语句不能说出for循环?此外,是否有可能在不首先返回功能的情况下实现这样的功能?
chq*_*lie 44
你不能用break;这种方式,它必须出现在for循环体内.
有几种方法可以做到这一点,但不推荐:
您可以使用该exit()功能退出程序.由于循环是从它运行的,main()并且你之后没有做任何事情,所以可以通过这种方式实现你想要的东西,但它是一个特例.
您可以在函数中设置全局变量,并for在函数调用后在循环中测试它.通常不建议使用全局变量.
你可以使用setjmp()和longjmp(),但这就像试图用锤子击打苍蝇,你可能会破坏其他东西并完全错过苍蝇.我不推荐这种方法.此外,它需要jmpbuf您必须传递给函数或作为全局变量访问.
可接受的替代方法是将status变量的地址作为额外参数传递:函数可以将其设置为指示需要从循环中断.
但到目前为止,C中最好的方法是返回一个值来测试延续,它是最可读的.
根据你的解释,你没有源代码,foo()但可以检测一个你可以直接或间接调用的函数中的某些条件foo():longjmp()将从它的位置跳出,深入内部foo(),可能是调用堆栈的多个层次到该setjmp()位置,绕过所有中间呼叫的常规功能退出代码.如果这正是您需要做的以避免崩溃,setjmp()/ longjmp()是一个解决方案,但它可能会导致其他问题,如资源泄漏,缺少初始化,不一致状态和其他未定义行为的来源.
请注意,您的for循环将迭代101次数,因为您使用<=运算符.惯用for循环用于for (int i = 0; i < 100; i++)精确迭代显示为上(排除)边界的次数.
Tho*_*thy 24
break,就像goto,只能在同一个函数中本地跳转,但如果你绝对必须,你可以使用setjmp和longjmp:
#include <stdio.h>
#include <setjmp.h>
jmp_buf jump_target;
void foo(void)
{
printf("Inside foo!\n");
longjmp(jump_target, 1);
printf("Still inside foo!\n");
}
int main(void) {
if (setjmp(jump_target) == 0)
foo();
else
printf("Jumped out!\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
呼叫longjmp将导致跳回setjmp呼叫.返回值setjmp显示是否在设置跳转目标后返回,或者是否从跳转返回.
输出:
Inside foo!
Jumped out!
Run Code Online (Sandbox Code Playgroud)
如果使用正确,非局部跳跃是安全的,但有许多事情需要仔细考虑:
longjmp跳过"通过" setjmp调用和longjmp调用之间的所有函数激活,如果这些函数中的任何一个期望能够在执行当前位置之后执行额外的工作,那么将无法完成该工作.setjmp已终止,则行为未定义.任何事情都可能发生.setjmp尚未调用,则jump_target未设置,并且行为未定义.setjmp某些条件下可能具有未定义的值.setjmp调用.如果你对机器指令和CPU寄存器的非本地跳转有很好的理解,那么大多数都会自然地遵循,但除非你有这个,并且已经阅读了C标准的功能并且不能保证,我会建议一些警告.
(注意:自从我最初编写此问题以来,该问题已被编辑)
由于编译C的方式,它必须知道在调用函数时中断的位置.既然你可以从任何地方调用它,甚至某个地方都没有意义,你就不能break;在你的函数中有一个声明并让它像这样工作.
其他答案提出了可怕的解决方案,例如设置全局变量,使用#define函数或跳转(!).这些都是极差的解决方案.相反,您应该使用在开头段落中错误地解除的解决方案,并从函数中返回一个值,该值指示break在这种情况下您要触发的状态并执行以下操作:
#include <stdbool.h>
bool checkAndDisplay(int n)
{
printf("%d\n", n);
return (n == 14);
}
int main(void) {
for (int i = 0; i <= 100; i++) {
if (checkAndDisplay(i))
break;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
试图找到模糊的方法来实现这样的事情而不是使用正确的方法来实现相同的最终结果是一种可靠的方法来生成可怕的质量代码,这是维护和调试的噩梦.
你提到,隐藏在注释中,你必须使用void返回,这不是问题,只需将break参数作为指针传递:
#include <stdbool.h>
void checkAndDisplay(int n, bool* wantBreak)
{
printf("%d\n", n);
if (n == 14)
wantBreak = true;
}
int main(void) {
bool wantBreak = false;
for (int i = 0; i <= 100; i++) {
checkAndDisplay(i, &wantBreak);
if (wantBreak)
break;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
由于您的参数是固定类型,我建议您使用强制转换将指针传递给其中一个参数,例如 foo(a, b, (long)&out);
如果无法使用该break指令,则可以在模块中定义局部变量,并在for循环中添加第二个运行条件.例如,如下代码:
#include <stdio.h>
#include <stdbool.h>
static bool continueLoop = true;
void foo (int a)
{
bool doBreak = true;
printf("a: %d",a);
if(doBreak == true){
continueLoop = false;
}
else {
continueLoop = true;
}
}
int main(void) {
continueLoop = true; // Has to be true before entering the loop
for (int i = 0; (i <= 100) && continueLoop; i++)
{
foo(i);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
请注意,在此示例中,这不完全是break-instruction,但for循环不会执行另一次迭代.如果你想做一个,break你必须插入一个if变量的条件continueLoop,导致break:
int main(void) {
continueLoop = true; // Has to be true before entering the loop
for (int i = 0; i <= 100; i++)
{
foo(i);
if(!continueLoop){
break;
}
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)