如何保护枚举赋值
How to protect enum assignment
我想防止无效值枚举赋值。我知道即使我什至分配不在枚举中的值它也会起作用。示例:
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;
}
对我来说,我的解决方案效率低下,如果我有更多的枚举和更多的枚举值,我该如何写这个?
无法警告分配适合枚举的整数。
C 中的枚举数是整数类型的同义词。假设为 enum example_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;
基本上,如果您想将类型限制为特定值,则需要执行检查。
只要 enum
是连续的,就可以这样做:
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; }
另一种选择是不预先验证枚举值,但一旦代码检测到无效值就会出错:
switch(input) {
case ENUM_VAL0: ... break;
case ENUM_VAL1: ... break;
...
default:
assert(0 && "broken enum");
break;
}
但是在 C 中没有办法强制 enum
值不超出范围。如果你想保护 enum
fiddling 是将值隐藏在 struct
中,然后具有操作 struct
的功能。函数和 struct
实现可以通过 .h
文件中的前向声明和 .c
文件中的实现向用户隐藏:
struct example_t {
enum example_enum value;
}
void example_set_val0(example_t* v) { v->value = ENUM_VAL0; }
如果有人对此主题感兴趣,我这里有一些有效的解决方案。
typed_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_class_example.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;
}
优点:
- 枚举值赋值与结构赋值类似
- 指针枚举也有效
- 无法更改枚举值
缺点:
- 不能在开关中使用
- 不能直接比较
- 不能直接return枚举数值
注意:很抱歉在这里滥用预处理器
我想防止无效值枚举赋值。我知道即使我什至分配不在枚举中的值它也会起作用。示例:
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;
}
对我来说,我的解决方案效率低下,如果我有更多的枚举和更多的枚举值,我该如何写这个?
无法警告分配适合枚举的整数。
C 中的枚举数是整数类型的同义词。假设为 enum example_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;
基本上,如果您想将类型限制为特定值,则需要执行检查。
只要 enum
是连续的,就可以这样做:
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; }
另一种选择是不预先验证枚举值,但一旦代码检测到无效值就会出错:
switch(input) {
case ENUM_VAL0: ... break;
case ENUM_VAL1: ... break;
...
default:
assert(0 && "broken enum");
break;
}
但是在 C 中没有办法强制 enum
值不超出范围。如果你想保护 enum
fiddling 是将值隐藏在 struct
中,然后具有操作 struct
的功能。函数和 struct
实现可以通过 .h
文件中的前向声明和 .c
文件中的实现向用户隐藏:
struct example_t {
enum example_enum value;
}
void example_set_val0(example_t* v) { v->value = ENUM_VAL0; }
如果有人对此主题感兴趣,我这里有一些有效的解决方案。
typed_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_class_example.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;
}
优点:
- 枚举值赋值与结构赋值类似
- 指针枚举也有效
- 无法更改枚举值
缺点:
- 不能在开关中使用
- 不能直接比较
- 不能直接return枚举数值
注意:很抱歉在这里滥用预处理器