简体   繁体   English

'Typesafe'枚举,以避免检查C中的数组索引

[英]'Typesafe' enum to avoid check for array index in C

Is it a suitable approach to restrict the parameters of function with a 'typesafe' enum to avoid the check for array index out of bounds? 是否使用“类型安全”枚举来限制函数参数的合适方法,以避免检查数组索引超出范围?

I have a module which holds the data of its instances in an Array. 我有一个模块,可将其实例的数据保存在Array中。 The data of an instance should be accessed from outside the module with an index. 实例的数据应使用索引从模块外部访问。 There will be several interface functions and i would like to avoid several if-statements. 将有几个接口函数,我想避免几个if语句。

Following example: 以下示例:

// 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
}

The example in one file: https://repl.it/repls/QuarrelsomeDotingComputation 一个文件中的示例: https : //repl.it/repls/QuarrelsomeDotingComputation

Unfortunately, C is very tolerant with enums. 不幸的是,C对枚举非常宽容。 An enum is only a list of symbolic constants and you can always trick it by using the underlying type. 枚举只是符号常量的列表,您始终可以使用基础类型来欺骗它。 Here 这里

instance_print_v((instance_tst){2});    // does compile

does compile fine (not even a warning) and causes the access past the end of the array that you tried to prevent. 确实编译正常(甚至没有警告),并且导致访问超出了您试图阻止的数组末尾。

This approach will not prevent someone from using compound literals, like 这种方法不会阻止某人使用复合文字,例如

instance_print_v(((instance_tst){2}));

So rather have 所以宁可

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");
    }
}

Adapting your code to the trick I invented here: How to create type safe enums? 使您的代码适应我在这里发明的技巧: 如何创建类型安全的枚举? , then I'm ending up with something like this: ,那么我最终得到的是这样的东西:

#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
}

Unfortunately this will also block a instance_tst variable from getting passed to the function, but as I understand it, that's not a problem here. 不幸的是,这也将阻止instance_tst变量传递给函数,但是据我所知,这不是问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM