我遇到了以下代码,我试图了解该代码的工作原理以及使用它的原因。
enum eKeyEvent
{
eNoEvent = 0,
eKeyChanged
};
typedef enum eKeyEvent eKeyEvent_t;
typedef struct {
unsigned int ButtonMatrix;
unsigned int ChangedMask;
}
KeypadEvent_t;
static unsigned int KP_Sample;
static unsigned int KP_Last;
static unsigned int KP_Changed;
static unsigned int KP_Stable;
static unsigned char KP_DebounceCounter;
此代码是作为矩阵键盘扫描的示例给出的,但我想这是假设每个人都会理解的。如果我能理解它是如何工作的,我就会理解其余的代码。
我已经查找了数据类型(请原谅我在这里没有使用正确的术语;我是自学的),但我仍然对这一行感到困惑: typedef enum eKeyEvent eKeyEvent_t;该结构让我困惑可能是因为我不理解 typedef 枚举。
enum
、struct
和union
特别有自己的小(钝)类型命名机制,称为“标签”。在 enum eKeyEvent
中,eKeyEvent
是一个标签,您可以使用标签 struct KeypadEvent_t
等类似地命名该结构。
在这种情况下,关键字+标签,
enum eKeyEvent
,构成了一个类型。这意味着每次你想声明该类型的变量时,你必须输入:
enum eKeyEvent my_event;
typedef
消除了这种需要,使用typedef
您只需输入:
eKeyEvent_t my_event;
使用哪一种被认为是风格问题。后一种形式是迄今为止最常见的形式,使您的自定义类型的行为与其他默认类型类似。
将
typedef
与 enum
声明一起编写可能更常见,就像对结构所做的那样。这是 100% 等效的:
typedef enum eKeyEvent // we don't even need the tag name here
{
eNoEvent = 0,
eKeyChanged
} eKeyEvent_t;
让事情变得更混乱的是,标签存在于自己独特的命名空间中,而
typedef
名称类型最终与变量和函数名称等一起出现在正常的标识符命名空间中。所以这也是合法的代码:
typedef struct KeypadEvent_t { // this is a struct tag
unsigned int ButtonMatrix;
unsigned int ChangedMask;
} KeypadEvent_t; // this is a type name identifier
现在我们可以将此结构体称为
struct KeypadEvent_t
(标签)或 KeypadEvent_t
(typedef 名称标识符),它将表示相同的结构体。并且两种形式100%兼容。
标签并不是一个完全多余的功能,我们可以将它们用于自引用结构:
typedef struct node
{
/* stuff here */
struct node* next;
} node_t;
这是定义链表中节点的常用方法。感谢标签,我们可以在完成声明之前自引用该结构。但从现在开始,我们可以将其称为
node_t
,并将 next
视为 node_t*
。
enum eKeyEvent
{
eNoEvent = 0,
eKeyChanged
};
typedef enum eKeyEvent eKeyEvent_t;
我不知道作者为什么把它分成两个声明。在这种情况下,没有理由这样做。
可以声明为:
typdef enum eKeyEvent
{
eNoEvent = 0,
eKeyChanged
}eKeyEvent_t;
或不带标签:
typedef enum
{
eNoEvent = 0,
eKeyChanged
}eKeyEvent_t;
如果是“前向声明”以将类型用作“不完整类型”,则使用标签拆分声明是有意义的
typedef enum eKeyEvent eKeyEvent_t;
struct foo
{
eKeyEvent_t *x;
};
struct foo y;
int bar(eKeyEvent_t *x)
{
return !!x;
}