如何根据表的大小导出常量

时间:2013-09-01 17:13:25

标签: c

我有一个库函数,它接受一个level参数,并使用它来索引一个参数值数组,我正在从函数的使用者中抽象出来。请注意,参数表,甚至其结构类型仅对其包含的C文件可见。

library.h

#define MIN_LEVEL   0
#define MAX_LEVEL   ((sizeof(m_param_table)/sizeof(m_param_table[0]))-1)

BOOL set_param_level(int level);

LIBRARY.C

#include "library.h"

typedef struct {
   int param1;
   int param2;
} params_t;

// Parameters table - static (local) to this C file
static params_t m_param_table[] = {
   {0, 1},
   {2, 3},
};

BOOL set_param_level(int level) {
   int p1, p2;

   // bounds checking on MIN_LEVEL and MAX_LEVEL
   if (level < MIN_LEVEL) return FALSE;
   if (level > MAX_LEVEL) return FALSE;

   p1 = m_param_table[level].param1;
   p2 = m_param_table[level].param2;

   // do stuff with p1, p2

   return TRUE;
}

consumer.c

#include "library.h"

// Limit user input to MIN_LEVEL and MAX_LEVEL

set_param_level( user_input_value );

我希望consumer.c能够访问MIN_LEVELMAX_LEVEL,以进行用户输入验证。但显然,他无法访问m_param_table,因此这些宏不起作用。

最优雅且正确的方式是什么?选项包括:

1)将typedef ... params_t移至标头文件,然后从static移除m_params_table。显然我不喜欢这样,因为它会使这些东西不必要地显而易见。

2)对头文件中的值进行硬编码。当然,硬编码的数据很糟糕。

3 个答案:

答案 0 :(得分:5)

您有第三种选择:

MIN_LEVELMAX_LEVEL移至library.c并创建get_min_level()中声明并在get_max_level()中实施的新功能library.hlibrary.c只需分别返回MIN_LEVELMAX_LEVEL。这些函数将在consumer.c中显示,而不会泄露库的内部数据结构。

答案 1 :(得分:1)

编辑:添加了const关键字

一种选择是使用外部。

首先,MIN_LEVEL和MAX_LEVEL不应该在library.h中,而应该在library.c中。正如您所指出的,没有m_param_table的定义,消费者无法使用此头文件。而且你不应该只是为了提供对这些常量的访问而公开。这就是你能做的。

在library.h中:

extern const int min_level;
extern const int max_level;

BOOL set_param_level(int level);

在library.c中:

...

#define MIN_LEVEL   0
#define MAX_LEVEL   ((sizeof(m_param_table)/sizeof(m_param_table[0]))-1)

const int min_level = MIN_LEVEL;
const int max_level = MAX_LEVEL;

这使得常量可供消费者使用,而不会暴露私人内部。

答案 2 :(得分:1)

好吧,如果你希望你的值是常量,同时你更喜欢隐藏表和相关的类型声明,那么一个解决方案就是确实对这些值进行硬编码,但同时添加.c文件中的静态断言,确保硬编码值始终是最新的。

所以,在头文件中你做

#define MIN_LEVEL   0
#define MAX_LEVEL   1

.c文件中

static params_t m_param_table[] = {
   {0, 1},
   {2, 3},
};

STATIC_ASSERT(MIN_LEVEL == 0);
STATIC_ASSERT(MAX_LEVEL == sizeof m_param_table / sizeof *m_param_table - 1);

(在C中使用您最喜欢的STATIC_ASSERT实现。

这种方法消除了硬编码值吮吸的最重要原因之一:他们倾向于悄然过时。