';类型安全';枚举以避免在C中检查数组索引
使用“类型安全”枚举限制函数的参数是否合适,以避免检查数组索引是否超出范围 我有一个模块,它将其实例的数据保存在一个数组中。实例的数据应该通过索引从模块外部访问。将有几个接口函数,我希望避免使用几个if语句 以下示例:';类型安全';枚举以避免在C中检查数组索引,c,arrays,C,Arrays,使用“类型安全”枚举限制函数的参数是否合适,以避免检查数组索引是否超出范围 我有一个模块,它将其实例的数据保存在一个数组中。实例的数据应该通过索引从模块外部访问。将有几个接口函数,我希望避免使用几个if语句 以下示例: // In myInstanceModule.h typedef struct { enum { FIRST, SECOND } index_e; } instance_tst; #define FIRST_INSTANCE (instance_tst){ FIRST } #
// In myInstanceModule.h
typedef struct { enum { FIRST, SECOND } index_e; } instance_tst;
#define FIRST_INSTANCE (instance_tst){ FIRST }
#define SECOND_INSTANCE (instance_tst){ SECOND }
void instance_init_v();
void instance_print_v(instance_tst instance);
// In myInstanceModule.c
#define MEMBER_COUNT 2
typedef struct myArray {
int myValue;
}myArray_tst;
static myArray_tst myMembers_ast[MEMBER_COUNT];
void instance_init_v() {
for (int i = 0; i < MEMBER_COUNT; i++)
{
myMembers_ast[i].myValue = i * 10;
}
}
void instance_print_v(instance_tst instance) {
printf("Value of this instance is: %d \n", myMembers_ast[instance.index_e].myValue);
}
// In main.c
#include myModule.h
int main(void)
{
int test = 1234;
instance_init_v();
instance_print_v(FIRST_INSTANCE); // ok
instance_print_v(SECOND_INSTANCE); // ok
//instance_print_v((instance_tst)2); // does not compile
//instance_print_v(test); // does not compile
//instance_print_v(1); // does not compile
//instance_print_v(NULL); // does not compile
}
//在myInstanceModule.h中
typedef结构{enum{FIRST,SECOND}索引}实例};
#定义第一个实例(实例_tst){FIRST}
#定义第二个_实例(实例_tst){SECOND}
void instance_init_v();
作废实例打印(实例打印实例);
//在myInstanceModule.c中
#定义成员计数2
类型定义结构myArray{
int-myValue;
}myArray_tst;
静态myArray_tst myMembers_ast[成员计数];
void instance_init_v(){
对于(int i=0;i
一个文件中的示例:不幸的是,C对枚举非常宽容。枚举只是符号常量的列表,您可以通过使用基础类型来欺骗它。这里
instance_print_v((instance_tst){2}); // does compile
编译没有问题(甚至没有警告),并导致访问超过您试图阻止的数组的末尾。这种方法不会阻止某人使用复合文本,例如
instance_print_v(((instance_tst){2}));
我宁愿这样做
void instance_print_v(size_t index){
if(index < sizeof(myMembers_ast)/sizeof(myMembers_ast[0]))
{
printf("Value of this instance is: %d \n", myMembers_ast[index].myValue);
}
else
{
printf("Value of this instance is: undefined");
}
}
void实例打印(大小索引){
if(索引
根据我在这里发明的技巧调整您的代码:,然后我会得到如下结果:
#include <stdio.h>
// In myInstanceModule.h
typedef enum
{
FIRST,
SECOND
} instance_tst;
typedef union
{
instance_tst FIRST;
instance_tst SECOND;
} typesafe_instance_t;
#define instance_assign(var, val) _Generic((var), \
instance_tst: (var) = (typesafe_instance_t){ .val = val }.val )
void instance_init_v();
void instance_print (instance_tst instance); // the actual function
// type-safe wrapper:
#define instance_print_v(val) instance_print( instance_assign((instance_tst){0}, val) )
// In myInstanceModule.c
#define MEMBER_COUNT 2
typedef struct myArray {
int myValue;
}myArray_tst;
static myArray_tst myMembers_ast[MEMBER_COUNT];
void instance_init_v() {
for (int i = 0; i < MEMBER_COUNT; i++)
{
myMembers_ast[i].myValue = i * 10;
}
}
void instance_print (instance_tst instance) {
printf("Value of this instance is: %d \n", myMembers_ast[instance].myValue);
}
// In main.c
int main(void)
{
int test = 1234;
instance_init_v();
instance_print_v(FIRST); // ok
instance_print_v(SECOND); // ok
//instance_print_v((instance_tst)2); // does not compile
//instance_print_v(test); // does not compile
//instance_print_v(1); // does not compile
//instance_print_v(NULL); // does not compile
//instance_print_v((instance_tst){20}); // does not compile
}
#包括
//在myInstanceModule.h中
类型定义枚举
{
第一,
第二
}实例(t);
typedef联合
{
先例;
实例二;
}类型安全实例;
#定义实例分配(var,val)通用((var)\
实例_tst:(var)=(typesafe_实例_t{.val=val}.val)
void instance_init_v();
无效实例_打印(实例_tst实例);//实际功能
//类型安全包装器:
#定义实例_print_v(val)实例_print(实例_赋值((实例_tst){0},val))
//在myInstanceModule.c中
#定义成员计数2
类型定义结构myArray{
int-myValue;
}myArray_tst;
静态myArray_tst myMembers_ast[成员计数];
void instance_init_v(){
对于(int i=0;i
不幸的是,这也会阻止
instance\u tst
变量传递到函数,但据我所知,这不是问题。您错过了最明显的滥用方式:tryinstance\u print\v((instance\u tst){20})代码>哦,对了。非常感谢你。你有没有办法摆脱它?没有,除了使用范围检查之外,我没有别的解决办法。但这正是你想要避免的(相关:。在我所看到的由于数组边界而导致的所有崩溃和内存损坏之后,我建议您始终检查它们。给自己一个更轻松的生活。免责声明:积分应该转到@Gerhardh,他在我测试时在评论中回答了这一问题…公平地说,像这样的简单边界检查可能是最好的解决方案。其他解决方案ns可能看起来很优雅,但它们增加了很多复杂性。