简短的回答标题中的问题:
- 不能使用的返回值也可作为诊断,如果在返回类型的范围内的所有值都被认为是有效的(在非感 - 错误,非诊断)返回值。
- 使用魔术值而不是布尔标准值作为错误报告(如果这些标准值可能是函数的有效结果,则需要使用这些值)会创建(稍微)漏泄的抽象。
你看到的是使用时,一个希望有多个返回值,或者更可能很多有条件的返回值。
你的假设......
在这里,而不是更新*index
的,我们可以返回的i
价值,实现同样的事情,像下面。
...是错误的:
*index
是无符号整数,因此具有2 ^(32-1)为有效值范围是0。 这些值中的每一个似乎都是有效的索引值。因此,您有2^32 有效的结果。
为了表明失败,不使用具有多个返回值的“技巧”,您需要返回一个没有有效含义的值,因此能够带有作为失败指示的特殊含义。假设只有失败的迹象(并且没有详细的错误值),你会有1 无效的结果值。
这留给你用2^32 + 1 可能结果值,这不会在一个32位无符号整数适应(并且也不适合在你的示例使用int
)。
可能的解决方案是扩大返回值的范围,例如,通过使用64位无符号整数。然后,你可以使用值2^32(这是有效的值的范围之外),和指示失败:
#define MAGIC_FAILURE (((uint64_t) 1) << 32)
static uint64_t find_block(const char *name)
{
uint32_t i;
for (i = 0; i < ODP_CONFIG_SHM_BLOCKS; i++) {
if (strcmp(name, odp_shm_tbl->block[i].name) == 0) {
/* found it */
return i;
}
}
// return magic value indicating failure
return MAGIC_FAILURE;
}
我认为这是不好的做法,因为要了解功能,您还需要有魔法值在你的脑海里。还要考虑调试这个函数(或某个调用者):检查原始函数(通过指针返回数据)的返回值并查看布尔值(哪个用于哪个)而非必须去除返回值以确定是否有效。
最后一点:在这种情况下,虽然,我已经走了不同的方法:
static uint32_t find_block(const char *name)
{
uint32_t i;
for (i = 0; i < ODP_CONFIG_SHM_BLOCKS; i++) {
if (strcmp(name, odp_shm_tbl->block[i].name) == 0) {
/* found it */
return i;
}
}
return ODP_CONFIG_SHM_BLOCKS;
}
你可以使用它,因为,作为循环的实现表明,并不是每一个32位无符号整数是一个有效的索引(这留下空间表示失败的幻数)。使用明显相关的常量比一些随机魔术值更好。
虽然确实也考虑调用点:
uint32_t index;
if (! find_block("foo", &index)) {
// OMG
}
// all nice
在这里你只有函数名,当你想找到它的名字块这是你所需要的。
int32_t index = find_block("foo");
if (index == ODP_CONFIG_SHM_BLOCKS) {
// OMG
}
// all nice
这里,另一方面则需要以按名称查找一个块中的两个“东西”:函数名以及魔法值。这可能被认为是抽象中的泄漏。
该函数已经返回一个布尔结果。除了通过指针参数,还有其他的值会传递给调用者吗? – Olaf
您可能会返回索引值,或者类似-1的“未找到”。然后,您需要分支代码,具体取决于返回的值。这是许多UNIX系统调用所做的。 –
这显然是一个只有内部连接的函数(参见'static')。看看调用它的代码,这可能解释了选择。 – Olaf