C中的typedef枚举解释



我正在查看微控制器上ADC的头文件,其中包含以下代码。

/**
 * ADC channels type.
*/
typedef enum {
    ADC_CH_0,
    ADC_CH_1,
    ADC_CH_2,
    ADC_CH_3,
    ADC_CH_4,
    ADC_CH_5,
    ADC_CH_6, 
} adc_channel_t;

在 ADC 的 main.c 中,有以下代码行

adc_channel_t channels[] = {ADC_CH_4, ADC_CH_5};

我想知道为什么需要为 ADC 声明新的数据类型? typedef enum 是什么意思?

谢谢

作为artm答案的补充,typedef被添加到enum前面,以方便使用enum。声明是否如下所示:

enum adc_channel_t {
    ADC_CH_0,
    ADC_CH_1,
    ADC_CH_2,
    ADC_CH_3,
    ADC_CH_4,
    ADC_CH_5,
    ADC_CH_6, 
};

然后,adc_channel_t channels[] = {ADC_CH_4, ADC_CH_5};行必须写成:

enum adc_channel_t channels[] = {ADC_CH_4, ADC_CH_5};

typedef允许我们在每次使用该类型时忽略enum

使用有用的常量通常比"幻数"更受欢迎,尽管在这种情况下常量几乎没有提供额外的信息,这似乎有点奇怪。但是,它可能很有用,因为枚举器用作额外的描述。例如,您的 IDE 需要 adc_channel_t 类型的值,它将能够建议通道:通过ADC_CH_6 ADC_CH_0可能是值的有效范围,而不是简单地告诉您使用数字。

为什么这样做有多个组成部分。

  1. typedef 是做什么的
  2. 为什么要对枚举进行类型定义

typedef允许您定义新类型。这使您可以更清楚地表达您的意图。

 char id; // but my id is a number!
 typedef unsigned char uint8; // ok now we can use uint8 instead of char
 uint8 id; // better! Now we know we should only interpret id as a number.

在 C 中,您需要始终指定enumstruct 引用它们:

enum CarModels_e {
    Bravia,
    Uno
};

enum CarModels_e the_model;
enum CarModels_e other_model
// this gets boring fast...

所以程序员(懒惰的人(会尽量避免打字太多。为此,他们创建了一个新类型:

typedef enum CarModels_e CarModels; // now we don't need to type enum every time!
CarModels the_model;
CarModels other_model
// Less typing! Happier programmer!

但是您仍然必须键入两次enum CarModels_e以便它们也将其组合在一个声明中:

typedef enum /* Don't even need a name here anymore! Much less typing :) */ {
    Bravia,
    Uno
} CarModels;
<小时 />

为什么直接使用enum而不是数字?因为这样你就可以赋予数字以意义。因此,下次他们(或其他任何人(阅读他们的代码时,他们仍然知道这些数字是关于什么的。

// Example
if (measured_frequency == 12345) { // hmm where does this come from?
if (measured_frequency == MaximumMotorFrequency) { // Ah! Now i'll know what this is about in ten years!

我想知道为什么需要为 ADC 声明新的数据类型? typedef enum 是什么意思?

typedef enum 是一种对相关常量进行分组的方法。相反,您可以声明从 ADC_CH_0ADC_CH_6 的七个const,但由于它们都是相关的,因此最好在此处使用 enum(默认情况下,每个enum常量增加 1(。

稍后可以使用类型 adc_channel_t 来声明变量,并保证范围在声明的枚举常量内。

我的首选方法如下:

typedef enum powerState_tag {
    PS_OFF,
    PS_ON
} powerState_te;

这会在一个表达式中执行多项操作。

  1. 声明枚举pwerState_tag {PS_OFF, PS_ON}。
  2. 创建 powerState_te 的类型定义。

我通常会添加pwerState_tag以便某些代码解析器/编辑器将枚举显示为未命名。我添加后缀以指示_tag是枚举的名称,_te是类型化的枚举。为了对称,我在_tag和_te中复制了这个名字。这些不是标准化的命名约定,可以命名为您想要的任何名称,除非您的编码标准另有说明。巴尔集团有一个在线标准,我在几个工作中看到了参考,而且非常好。不过,他们不会使用_te来识别它是什么类型的 typedef。

以这种方式定义类型枚举的最大好处是,如果有人传入未定义的值,编译器会在编译时通知您。

例如,在上面的示例中,以下内容会导致编译时错误:

adc_channel_t channels[] = {99, -1};

但以下内容不会失败,因为枚举中包含 4 和 5:

adc_channel_t channels[] = {4, 5};

一些编辑器也使用 typedef 枚举来自动填充。

adc_channel_t channel;
// when you begin to assign the value, the editor will offer suggestions
channel = AD \<auto completes up to _> and you have to merely type the number of click the value you like. 

我使用过的大多数不使用 typedef 枚举模式的代码都会传入泛型 int,而不会指定它是枚举和利用ADC_CH_4,就像 #define 一样。

uint8_t getAdcVal(uint8_t channel); // A
uint8_t getAdcVal(adc_channel_t channel); //B

虽然 A 在用户使用有效范围时正常运行,但编译器不会像 B 那样在编译时验证它是否在枚举范围内。

巴尔集团的编码标准

让我们分别了解typedefenum

枚举

它是一种用户定义的数据类型,用于将名称分配给整数常量。就像#define,但两者之间有区别他们,我们将在答案的后面部分讨论。

请考虑以下示例代码:

enum bool{
FALSE, 
TRUE
};

这里发生的事情是我们正在定义一种 bool 类型的数据类型,它有两个名称 - FALSE 和 TRUE。编译器初始化这些常量的值,下一个名称的值相对于前一个值递增 1。在我们的例子中,FALSE 的值将为 0,TRUE 的值将为 1。如果我们赋值 FALSE 为 6,则 TRUE(在 FALSE 之后(的值将是 FALSE++,即 7。我们可以自己初始化值,数据结构中的两个或所有名称可以具有相同的值。问题是,当我们有#define时,为什么要使用枚举?答案是因为:

    枚举
  1. 是作用域的本地枚举
  2. 编译器初始化值注意:所有名称在作用域中必须是唯一的,并且只能是完整的允许常量作为名称的值。

类型定义

考虑我们的示例,其中我们已经定义了数据类型,现在我们想在代码中使用它。您可以使用它的方法是:

enum bool var; //declared a variable var of type enum bool
var  = FALSE; 

这种声明的问题是,每次要声明时,都必须在该类型的变量之前键入enum bool。所以我们要做的是给数据类型(enum bool(一个昵称或别名,每当我们想在代码中使用它时,我们都可以声明一个变量,该变量的类型是赋予数据类型的昵称。typedef 关键字用于为数据类型提供昵称。例:

typedef enum bool{
FALSE,
TRUE
} BoolTypedef_t;

因此,每当我们想使用这种数据类型中的任何成员时,我们都可以像这样使用它:

BoolTypedef_t var; 
var = TRUE; 
printf("%d", var);

最新更新