C 如何保护枚举分配

C 如何保护枚举分配,c,testing,enums,compile-time,compile-time-constant,C,Testing,Enums,Compile Time,Compile Time Constant,我想防止无效值枚举赋值。我知道,即使我分配了不在枚举中的值,它也会工作。例如: enum example_enum { ENUM_VAL0, ENUM_VAL1, ENUM_VAL2, ENUM_VAL3 }; void example_function(void) { enum example_enum the_enum = ENUM_VAL3; // correct the_enum = 41; // will work the_enum = 0

我想防止无效值枚举赋值。我知道,即使我分配了不在枚举中的值,它也会工作。例如:

enum example_enum
{
    ENUM_VAL0,
    ENUM_VAL1,
    ENUM_VAL2,
    ENUM_VAL3
};

void example_function(void)
{
  enum example_enum the_enum = ENUM_VAL3; // correct
  the_enum = 41; // will work
  the_enum = 0xBADA55; // also will work
  bar(the_enum); // this function assumes that input parameter is correct
}
是否有简单有效的方法来检查对枚举的赋值是否正确?我可以通过函数测试值

void foo(enum example_enum the_enum)
{
  if (!is_enum(the_enum))
    return;

  // do something with valid enum
}
我可以通过以下方式解决此问题:

static int e_values[] = { ENUM_VAL0, ENUM_VAL1, ENUM_VAL2, ENUM_VAL3 };
int is_enum(int input)
{
  for (int i=0;i<4;i++)
    if (e_values[i] == input)
      return 1;
  return 0;
}
static int e_values[]={ENUM_VAL0,ENUM_VAL1,ENUM_VAL2,ENUM_VAL3};
int是_enum(int输入)
{

对于(int i=0;i,对于分配适合枚举的整数,没有任何警告方法

C中的枚举数是整数类型的同义词。假设为
enum example\u enum
选择的类型为int,则代码与:

void example_function(void)
{
  int the_enum = ENUM_VAL3; // correct
  the_enum = 12345; // will work
  bar(the_enum); // this function assumes that input parameter is correct
}

void foo(int the_enum)
{
  if (!is_enum(the_enum))
    return;
  // do something with valid enum
}
您可以使用结构,但即使这样也可以避免:

struct example_enum_struct e = { 12345 };
e.value = 23456;

基本上,如果要将类型限制为特定值,则需要执行检查。

只要
枚举是连续的,就可以执行以下操作:

static int e_values[] = { ENUM_VAL0, ENUM_VAL1, ENUM_VAL2, ENUM_VAL3, ENUM_VAL_COUNT };

int is_enum(int input) { return 0 <= input && input < ENUM_VAL_COUNT; }
但是没有办法强制执行
enum
值在C中完全不超出范围。如果要保护
enum
不被篡改,最好的办法是将值隐藏在
struct
中,然后使用函数操作
struct
。函数和
struct
实现用户可以通过
.h
文件中的转发声明和
.c
文件中的实现来隐藏该操作:

struct example_t {
     enum example_enum value;
}

void example_set_val0(example_t* v) { v->value = ENUM_VAL0; }

如果有人对这个话题感兴趣,我这里有一些可行的解决方案

类型化_enums.h

#ifndef TYPED_ENUMS_H
#define TYPED_ENUMS_H

#define TYPED_ENUM(name_) \
    typedef struct { int v; } name_

#define TYPED_ENUM_VALUE(name_, value_)       (name_) { value_ }
#define GET_TYPED_ENUM_VALUE(en_)             (en_.v)
#define TYPED_ENUM_EQ(a_, b_)                 (GET_TYPED_ENUM_VALUE(a_) == GET_TYPED_ENUM_VALUE(b_))

#endif
usb_class.h

#ifndef USB_CLASS_H
#define USB_CLASS_H

#include "typed_enums.h"

TYPED_ENUM(UsbClass);

#define USB_CLASS_BILLBOARD                     TYPED_ENUM_VALUE(UsbClass, 0x11)
#define USB_CLASS_TYPE_C_BRIDGE                 TYPED_ENUM_VALUE(UsbClass, 0x12)
#define USB_CLASS_DIAGNOSTIC_DEVICE             TYPED_ENUM_VALUE(UsbClass, 0xDC)
#define USB_CLASS_WIRELESS_CONTROLLER           TYPED_ENUM_VALUE(UsbClass, 0xE0)

#endif
usb_类_示例.c

#include "typed_enums.h"
#include "usb_class.h"

#include <stdio.h>

int main(int argc, char ** argv)
{
    UsbClass usbClass = USB_CLASS_WIRELESS_CONTROLLER;
    usbClass = 12345; // tadam!!!! throws error
    usbClass = USB_CLASS_VIDEO;
    if (TYPED_ENUM_EQ(usbClass, USB_CLASS_VIDEO)) {
        printf("usbClass = USB_CLASS_VIDEO\n");
    }

    printf("usb class value: %02X\n", GET_TYPED_ENUM_VALUE(usbClass));

    return 0;
}
#包括“typed_enums.h”
#包括“usb_class.h”
#包括
int main(int argc,字符**argv)
{
UsbClass UsbClass=USB_CLASS_无线_控制器;
usbClass=12345;//tadam!!!!抛出错误
usbClass=USB_CLASS_视频;
if(类型化枚举均衡器(USB类、USB类、视频)){
printf(“usbClass=USB_CLASS_VIDEO\n”);
}
printf(“usb类值:%02X\n”,获取类型的枚举值(usbClass));
返回0;
}
优点:

  • 枚举值赋值与结构赋值类似
  • 指针的枚举也可以工作
  • 无法更改枚举值
缺点:

  • 不能在开关中使用
  • 无法直接比较
  • 无法直接返回枚举数值

< P>注释:抱歉,这里的预处理器滥用了

编译器警告。使用断言。在C <代码> EnUM < /Calp> S实际上是代码> int <代码>。C不是C++。我想使用<代码>返回0。
#include "typed_enums.h"
#include "usb_class.h"

#include <stdio.h>

int main(int argc, char ** argv)
{
    UsbClass usbClass = USB_CLASS_WIRELESS_CONTROLLER;
    usbClass = 12345; // tadam!!!! throws error
    usbClass = USB_CLASS_VIDEO;
    if (TYPED_ENUM_EQ(usbClass, USB_CLASS_VIDEO)) {
        printf("usbClass = USB_CLASS_VIDEO\n");
    }

    printf("usb class value: %02X\n", GET_TYPED_ENUM_VALUE(usbClass));

    return 0;
}