当我编写代码时,我创建的更常见的错误类别之一是非一错误 (OBO)。在“真实”代码中,我经常在使用 C 或 C++ 进行复杂的指针/迭代器算术时遇到这个问题,但我有时在面试和作业(例如实现合并排序)问题中也遇到过问题,而我使用了其他编程语言。
我的典型调试策略包括随机交换<
and 和<=
,++var
并将orvar++
附加到变量,直到代码看起来可以工作。我很想知道存在哪些更好的策略或工具(例如静态分析、调试器/IDE 功能等)来发现 OBO。+ 1
- 1
我对诸如“避免 C 风格的循环”、“避免指针算术”、“函数式代码”或“使用不同的编程语言”之类的答案并不特别感兴趣。是的,这些事情可以缓解这个问题,但并不总是可以做到,而且它们并不能完全消除 OBO 的危险。
作为一个例子,我相信下面的代码,一个 C(或者它也是有效的 C++)实现strcpy(3)
,没有 OBO。但正如您所见,OBO 可能会出现数十个潜在问题领域。有什么方法可以轻松确认它实际上没有 OBO 吗?
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#if !defined(__GNUC__) && !defined(__attribute__)
#define __attribute__(X)
#endif
#ifdef __cplusplus
extern "C" {
#if defined(__GNUC__) || defined(_MSC_VER) || defined(__restrict)
#define restrict __restrict
#elif !defined(restrict)
#define restrict
#endif
#endif
static inline bool aligned8(const void *ptr) {return !((uintptr_t)ptr & 7);}
static inline bool aligned4(const void *ptr) {return !((uintptr_t)ptr & 3);}
static inline bool aligned2(const void *ptr) {return !((uintptr_t)ptr & 1);}
/* Positive return value is the greatest common alignment (≤8) of the pointers.
* Negative return value is the byte offset that when added to both pointers
* yields a pair of pointers with alignment ≥8.
*/
static inline int common_alignment(const void *p1, const void *p2) {
if (aligned8(p1)) {
if (aligned8(p2))
return 8;
else if (aligned4(p2))
return 4;
else if (aligned2(p2))
return 2;
} else if (aligned4(p1)) {
if (aligned8(p2))
return 4;
else if (aligned4(p2))
return -4;
else if (aligned2(p2))
return 2;
} else if (aligned2(p1)) {
if (aligned4(p2))
return 2;
else if (aligned2(p2))
return -6;
} else if (!aligned2(p2)) {
return -7;
}
return 1;
}
/* strcpy implementation
*/
__attribute__((nonnull))
size_t string_copy(char *restrict dst, const char *restrict src) {
size_t i = 0;
int align = common_alignment(dst, src);
if (align < 0) {
for (; i < (size_t)-align; ++i)
if (!(*dst++ = *src++))
return i;
align = 8;
}
const size_t mask = (size_t)align - 1;
#define ALIGNED_STRING_COPY_IMPL_(BITS) do {\
uint##BITS##_t *restrict dst##BITS = (uint##BITS##_t*)dst;\
while (*src++)\
if (!(++i & mask))\
*dst##BITS++ = *(const uint##BITS##_t *restrict)(src - align);\
dst = (char*)dst##BITS;\
} while (0)
if (align & 8) {
ALIGNED_STRING_COPY_IMPL_(64);
} else if (align & 4) {
ALIGNED_STRING_COPY_IMPL_(32);
} else if (align & 2) {
ALIGNED_STRING_COPY_IMPL_(16);
} else { // byte-aligned
while ((*dst++ = *src++))
++i;
return i;
}
const size_t offset = (i & mask) + 1;
memcpy(dst, src - offset, offset);
return i;
}
#ifdef __cplusplus
}
#endif