[英]Forcing the size of an enum'd field in a structure
[NOTE: this is related to Specifying size of enum type in C and What is the size of an enum in C? [注意:这与在C中指定枚举类型 的大小有关,并且在C中枚举的大小是多少? , but in those questions, the issue was how to minimize the size of the enclosing struct.
,但是在这些问题中,问题在于如何最小化封闭结构的大小。 Here, we want to specify the size of the individual members of the struct, but still get the documentation advantage of typedef'd enums]
在这里,我们要指定结构中各个成员的大小,但仍然可以获得typedef枚举的文档优势]
I'm implementing the client side of a serial communication protocol. 我正在实现串行通信协议的客户端。 I'd like to use C structs to capture the format of a serial packet, and I'd like to use C enums to define the legal values of the various slots in the packet.
我想使用C结构来捕获串行数据包的格式,并且我想使用C枚举来定义数据包中各个插槽的合法值。
I don't see a way to do both, but since I'm using GCC, it may be possible. 我看不到同时做到这两种方法的方法,但是由于我使用的是GCC,因此有可能实现。
As a hypothetical example of the problem, assume the packet I receive looks like this: 作为问题的假设示例,假设我收到的数据包如下所示:
typedef struct {
uint16_t appliance_type;
uint8_t voltage;
uint16_t crc;
} __attribute__((__packed__)) appliance_t;
That's pretty clear, and I'm pretty sure I'll get a struct that is five bytes long. 这很清楚,我很确定会得到一个五字节长的结构。 But it doesn't capture the fact that
appliance_type
and voltage
can only take on certain values. 但这并不能说明
appliance_type
和voltage
只能取某些值的事实。
I'd prefer something like this... 我更喜欢这样的东西...
typedef enum {
kRefrigerator = 600,
kToaster = 700,
kBlender = 800
} appliance_type_t;
typedef enum {
k120vac = 0,
k240vac = 1,
k12vdc = 2
} voltage_t;
typedef struct {
appliance_type_t appliance_type;
voltage_t voltage;
uint16_t crc;
} appliance_t;
...but there's no way that I know of to specify that appliance_type_t is 16 bits and voltage_t is 8 bits. ...但是我不知道要指定哪个device_type_t为16位,而voltage_t为8位。
Is there a way to have my cake and eat it too? 有办法吃我的蛋糕吗?
I need to make it clear that I'm NOT expecting the compiler to enforce the enum'd values as setters for the respective fields! 我需要说明的是,我不希望编译器将枚举值强制为各个字段的设置器! Rather, I find that typedef'd enums are a useful construct for maintainers of the code, since it makes explicit what the intended values are.
相反,我发现typedef枚举对于代码的维护者来说是一个有用的构造,因为它可以明确表明预期的值是什么。
Note: As I researched this, I noticed that GCC enums accept __attribute__
specifications, but I'm not sure that helps. 注意:在研究此内容时,我注意到GCC枚举接受
__attribute__
规范,但不确定是否有帮助。
One way of doing this would be to use the bit field with the definition of the member in the struct. 一种方法是将bit字段与结构中成员的定义一起使用。
So your struct would be - 所以你的结构是-
typedef struct {
appliance_type_t appliance_type:16;
voltage_t voltage:8;
uint16_t crc;
} appliance_t;
But this will leave a padding after the voltage field (depends on the implementation of the compiler though). 但这会在电压场之后留下填充(尽管取决于编译器的实现)。 The packed attribute should help you with that.
包装属性应该可以帮助您。
I would suggest that you keep the "raw data" separate from the abstraction. 我建议您将“原始数据”与抽象分开。 For example:
例如:
typedef struct {
uint16_t type;
uint8_t voltage;
uint16_t crc;
} __attribute__((__packed__)) raw_data_t;
typedef struct {
appliance_type_t type;
voltage_t voltage;
uint16_t crc;
} appliance_t;
inline appliance_t raw_data_to_appliance (const raw_data_t* raw)
{
appliance_t app =
{
.type = (appliance_type_t)raw->type,
.voltage = (voltage_t)raw->voltage,
.crc = raw->crc,
};
return app;
}
This shouldn't yield much overhead code. 这不会产生太多的开销代码。 See also How to create type safe enums?
另请参阅如何创建类型安全枚举?
So I understand that when you declare an enum, you have no control over its size and in 因此,我知道当您声明一个枚举时,您无法控制它的大小和大小。
typedef struct {
appliance_type_t appliance_type;
voltage_t voltage;
uint16_t crc;
} appliance_t;
you want eg voltage_t voltage
to be of a specific size, let's say uint8_t
but you are not able to specify that. 例如,您希望
voltage_t voltage
具有特定大小,例如uint8_t
但您无法指定该大小。
I don't know if you can provide size constraints on an enum, but there are two mechanisms you can use. 我不知道您是否可以对枚举提供大小限制,但是可以使用两种机制。 In both mechanisms you specify
unit8_t voltage
as the member of the struct: 在这两种机制中,都将
unit8_t voltage
指定unit8_t voltage
结构的成员:
typedef struct {
uint8_t appliance_type;
uint8_t voltage;
uint16_t crc;
} appliance_t;
Method 1 uses plain old #define
s. 方法1使用普通的旧
#define
。 You just #define the values and use the symbolic constants in assignments: 您只需#define值并在分配中使用符号常量:
#define k120vac 0
appliance.voltage= k120vac;
In method 2 you have the enums, but still declared a member of the size you want. 在方法2中,您具有枚举,但仍声明为所需大小的成员。 Now you can assign the enum values to the member, eg:
现在,您可以将枚举值分配给成员,例如:
appliance.voltage= k120vac;
voltage_t voltage;
voltage_t voltage;
declaration, you can do appliance.voltage= kToaster;
appliance.voltage= kToaster;
so not even gives the compiler "enum type safety" (checking only values from the domain are assigned/used), so not even that has been lost with the 2 methods I showed.
unsigned char x = k12vdc; // <== OK unsigned char y = kToaster; // <== warning: truncation of int to unsigned char
So it seems the compiler uses the smallest type possible for the values of the enum when assigning . 因此,似乎在分配时 ,编译器将最小的类型用于枚举的值。
There seems no size associated with the enum itself, only with its individual values. 枚举本身似乎没有大小相关联,仅与它的各个值有关。 Redefining
k12vdc= 2000
now also gives a warning on the assignment x= k12vdc
but not on x=k120vac
. 现在,重新定义
k12vdc= 2000
还会在分配x= k12vdc
发出警告,但不会在x=k120vac
上给出警告。
Now, given that the compiler (VC2008) doesn't enforce type safety of enums, and that you can't control the size of a variable or member of an enum type, there seems no use in declaring a variable or member of enum type, except maybe for documentation purposes. 现在,由于编译器(VC2008)并未强制枚举的类型安全,并且您无法控制变量或枚举类型的成员的大小,因此在声明变量或枚举类型的成员时似乎没有用,除非出于文档目的。 A variable/member of enum type will be the size of an int, as the following example shows:
变量/枚举类型的成员将是int的大小,如以下示例所示:
appliance_type_t a; voltage_t v; printf("sizeof appliance_type_t= %d\\n", sizeof(a)); // prints '4' printf("sizeof voltage_t= %d\\n", sizeof(v)); // prints '4'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.