让我们假设您有一个设置索引的函数,然后根据索引所指向的数组元素中存储的值更新少量变量。你检查索引以确保它在范围内吗? (在嵌入式系统环境中要特定的Arduino) 到目前为止,我已经为所有功能制作了一个安全且不安全的版本,这是一个好主意吗?在我的其他一些代码中,我注意到只有安全功能会导致多次检查条件随着库变大,所以我开始开发两者。安全功能检查条件并调用不安全功能,如下面的示例所示,用于上述情况。
安全版:
bool RcChannelModule::setFactorIndexAndUpdateBoundaries(factorIndex_T factorIndex)
{
if(factorIndex < N_FACTORS)
{
setFactorIndexAndUpdateBoundariesUnsafe(factorIndex);
return true;
}
return false;
}
不安全版本:
void RcChannelModule::setFactorIndexAndUpdateBoundariesUnsafe(factorIndex_T factorIndex)
{
setCuurentFactorIndexUnsafe(factorIndex);
updateOutputBoundaries();
}
如果我从根本上做错了,请告诉我为什么以及如何避免这种情况。另外我想知道,通常在您编程时,您是否认为未来的用户是傻瓜,或者您希望他们遵循提供的最少文档? (我说minimal的原因是因为我没有时间写一份适当的文件)
void RcChannelModule::setCuurentFactorIndexUnsafe(const factorIndex_T factorIndex)
{
currentFactorIndex_ = factorIndex;
}
答案 0 :(得分:4)
安全检查(例如数组索引范围检查,空检查等)旨在捕获编程错误。当这些检查失败时,没有正常恢复:程序可以做的最好的事情是记录发生的事情,然后重新启动。
因此,这些检查变得有用的唯一时间是在调试和测试代码期间。 C ++提供了通过asserts来处理这个问题的内置功能,它们保存在代码的调试版本中,但是从发布版本中编译出来:
void RcChannelModule::setFactorIndexAndUpdateBoundariesUnsafe(factorIndex_T factorIndex) {
assert(factorIndex < N_FACTORS);
setCuurentFactorIndexUnsafe(factorIndex);
updateOutputBoundaries();
}
注意: [当你创建一个供外部使用的库]时,每个外部函数的参数检查版本可能是有意义的,使用那些和所有内部函数的非参数检查实现。如果执行参数检查,那么(仅)在库和客户端代码之间的边界处执行。但是为用户提供选择毫无意义,因为如果你想保护他们免受使用错误的影响,那么你就不能依赖他们来选择&#34; safe&#34;你的功能的版本。 (John Bollinger)
答案 1 :(得分:0)
您是否制作了安全且不安全的功能版本,或者只是坚持使用安全版本?
对于更高级别的代码,我推荐一个版本,一个安全版本。
高级代码,具有大量相关功能和数据,数据和代码交互的组合无法在开发时完全检查。检测到错误时,应设置数据以指示错误状态。在这些函数中随后使用数据将意识到错误状态。
对于最低级时间的关键例程,我会选择@dasblinkenlight。创建一个源代码,每个调试和发布编译编译两种方式。
但请记住@pete becker,这可能是一个表现瓶颈吗?
使用浮点相关例程,使用NaN来帮助跟踪不可恢复的错误。
最后,能够,创建不会失败的功能并避免此问题。有许多,而不是全部,这只需要添加少量代码。它通常只会增加一个时间性能损失的常数而不是O(n)惩罚。
示例:考虑一个函数来删除字符串的第一个字符 - 就位。
// This work fine as long as s[0] != 0
char *slop_1(char *s) {
size_t len = strlen(s); // most work is here
return memmove(s, s + 1, len); // and here
}
而是定义函数并对其进行编码,以便在s[0] == 0
char *slop_2(char *s) {
size_t len = strlen(s);
if (len > 0) { // negligible additional work
memmove(s, s + 1, len);
}
return s;
}
类似的代码可以应用于OP example。请注意,至少在函数内是&#34;安全&#34; assert()
方案仍可用于发现开发问题。然而,没有assert()
的已发布代码仍会检查范围。
void RcChannelModule::setFactorIndexAndUpdateBoundaries(factorIndex_T factorIndex)
{
if(factorIndex < N_FACTORS) {
setFactorIndexAndUpdateBoundariesUnsafe(factorIndex);
} else {
assert(1);
}
}
答案 2 :(得分:0)
由于您标记了此Arduino和嵌入式,因此您拥有一个资源非常有限的系统,这是仍然制造的最疯狂的处理器之一。
在这样的系统上,您无法承受额外的错误处理。最好正确记录传递给函数的参数必须具有的值,然后将其检查留给调用者。
然后,调用者可以在运行时(如果需要)检查此项,或者在编译时使用静态断言进行检查。但是,您的函数无法将其实现为静态断言,因为它无法知道factorIndex
是运行时变量还是编译时常量。
至于&#34;我没有时间写出适当的文档&#34;,这是胡说八道。记录此功能所需的时间远远少于发布此SO问题所需的时间。你不必在一些Word文件中写一篇文章。你不一定要使用Doxygen或类似的东西。
但您确实需要编写最低文档:在头文件中,以注释的形式记录所有函数参数的用途和期望值。优选地,您应该具有如何记录这些功能的编码标准。以注释形式提供的公共API函数的最小文档是作为程序员的部分工作。在写完之前代码不完整。