Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C语言中安全递归是可能的吗?_C_Recursion_Undefined Behavior_Memory Safety - Fatal编程技术网

在C语言中安全递归是可能的吗?

在C语言中安全递归是可能的吗?,c,recursion,undefined-behavior,memory-safety,C,Recursion,Undefined Behavior,Memory Safety,如果C中的堆栈大小是一个实现细节,并且堆栈溢出是未定义的行为,那么在没有召唤鼻魔的情况下,是否可以执行任何递归 如果我递归遍历数据结构,给出一个简单的例子: struct tree { int leaf; struct tree *left; struct tree *right; } struct tree *get(const struct tree *t, int i) { if (t == NULL) return NULL; return i

如果C中的堆栈大小是一个实现细节,并且堆栈溢出是未定义的行为,那么在没有召唤鼻魔的情况下,是否可以执行任何递归

如果我递归遍历数据结构,给出一个简单的例子:

struct tree {
    int leaf;
    struct tree *left;
    struct tree *right; 
}
struct tree *get(const struct tree *t, int i) {
    if (t == NULL) return NULL;
    return i == t->leaf ? t : (i > t ? get(t->right) : get(t->left));
}

是否有某种类型的检查可以实现,以便本示例可以在遵循C编译器的任何标准上安全运行,是否有某种类型的宏,或者完全不可能,并且没有办法使本示例或任何类似模式安全?

在C99标准的基本原理中,第24页,讨论翻译限制:

该标准要求实现能够翻译和执行某些 满足每一个规定的限制。有人认为,这一标准给了决策者一个有用的自由度 在满足这些限制方面的实现者。而一个有缺陷的实现可能会成功 C89委员会认为,一个满足这一要求的程序仍然是无用的 这种独创性可能需要比制造有用的东西更多的工作。感觉 C89和C99委员会都认为实施者不应该解释翻译 限制为硬连线参数的值,但作为一组标准 将对执行情况进行判断


如果存在至少一个(可能是人为的和无用的)名义上执行给定翻译限制的程序,并且实现将以符合标准的方式进行处理,那么该实现对任何其他程序所做的任何操作都不会使其不符合标准。因此,实际上,任何程序都不可能有意义地避免未定义的行为,但该标准的作者预计,大多数实现将更多地关注使其有用所必需的内容,而不是试图达到该标准要求的最低限度。

我有一个具有256字节内存的微处理器。我不知道有多少堆栈帧,但不可能很多。如果函数是内联的,那么就没有问题了,但是您如何知道编译器的优化器可以做到这一点呢?相关:这看起来像是尾部递归,因此一个理智的优化编译器将在不使用太多堆栈的情况下生成代码。但是,您担心的是,没有人指定堆栈的最小大小,因此任何递归函数都可能因堆栈溢出而失败。但对于任何使用堆栈作为局部变量和/或返回地址的C函数,情况也是如此。因此,这个问题可以对任何C程序进行重新表述。@EugeneSh。问题是,该标准不需要“健全的优化编译器”,其中一些微处理器配备了专有编译器。因此,除非你知道它是由某个编译器编译的,否则一切都是徒劳的。@JerryJeremiah:该标准允许几乎任何编译器在给定几乎任何源文本的情况下以几乎任何方式进行操作,但作者希望实现在任何实际情况下都能尝试有用的行为。但在实践中,有没有办法确保使用递归的C程序在sane编译器中是内存安全的?@lemonhuman限制递归深度,假设您知道允许的堆栈大小。@lemonhuman:这取决于“确保”和“sane”的含义。没有简单的方法可以检查不同平台上的堆栈使用情况。在实践中,如果您的程序不使用非常大的堆栈帧,那么如果它超过台式机和电话等“大”系统上的堆栈,则可能会崩溃,而不是导致其他更隐蔽的错误,因为这些系统具有带有保护页的堆栈。在嵌入式系统上,如果您担心的话,您可能会想使用测试或分析对象文件。@lemonhuman:不幸的是,没有。绝大多数C实现使用“希望最好”语义。使用特定于实现的方法来度量堆栈使用情况,估计实现在每一层嵌套中似乎需要多少堆栈,并尝试确保可用堆栈超出估计的要求一个合理的限度。一些不支持递归的微型计算机的编译器可以做得更好,但该标准规定的对递归的支持不鼓励实现支持静态堆栈检查。@lemonhuman:BTW,我希望标准能够识别一类实现和程序,这样符合标准的实现就可以拒绝任何程序,但源文本可能要求某些行为保证,而实现就必须拒绝任何其保证无法实现的程序。这样的程序和实现类别将避免“一个程序规则”的需要,还可以解决程序员和编译器编写者之间关于“未定义行为”的许多冲突。