2016-01-26 12 views
2

我所经历的Linaro的ODP框架,看到这个代码片断,什么客观情况会妨碍将回报值用作诊断?

static int find_block(const char *name, uint32_t *index) 
{ 
    uint32_t i; 

    for (i = 0; i < ODP_CONFIG_SHM_BLOCKS; i++) { 
     if (strcmp(name, odp_shm_tbl->block[i].name) == 0) { 
      /* found it */ 
      if (index != NULL)                               
       *index = i; 

      return 1; 
     } 
    } 

    return 0; 
} 

在这里,而不是更新*index的,我们可以返回的i价值,实现同样的事情,像下面。

static int 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 -1; 
} 

除了品味,风格和编码指南 - 有没有什么客观的原因,为什么一个人必须选择一个,不能选择其他的?

+5

该函数已经返回一个布尔结果。除了通过指针参数,还有其他的值会传递给调用者吗? – Olaf

+0

您可能会返回索引值,或者类似-1的“未找到”。然后,您需要分支代码,具体取决于返回的值。这是许多UNIX系统调用所做的。 –

+0

这显然是一个只有内部连接的函数(参见'static')。看看调用它的代码,这可能解释了选择。 – Olaf

回答

1

简短的回答标题中的问题:

  • 不能使用的返回值也可作为诊断,如果在返回类型的范围内的所有值都被认为是有效的(在非感 - 错误,非诊断)返回值。
  • 使用魔术值而不是布尔标准值作为错误报告(如果这些标准值可能是函数的有效结果,则需要使用这些值)会创建(稍微)漏泄的抽象。

你看到的是使用时,一个希望有多个返回值,或者更可能很多有条件的返回值。

你的假设......

在这里,而不是更新*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 

这里,另一方面则需要以按名称查找一个块中的两个“东西”:函数名以及魔法值。这可能被认为是抽象中的泄漏。

相关问题