我正在查看微控制器上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枚举意味着什么?
由于
答案 0 :(得分:6)
作为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
。
使用有用的常量通常优于"魔术数字",虽然在这种情况下看起来有点奇怪但常量几乎不提供额外的信息。然而,它可以是有用的,因为枚举器用作额外的描述。例如,期望值为adc_channel_t
的IDE的IDE将能够建议可能是有效值范围的频道:ADC_CH_0
到ADC_CH_6
,而不是简单地告诉您使用数字。
答案 1 :(得分:4)
为什么要这样做有多个组成部分。
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语言中,你需要在引用时指定enum
和struct
:
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!
答案 2 :(得分:1)
我想知道你为什么需要为ADC声明新的数据类型?什么typedef枚举意味着什么?
typedef enum
是一种对相关常量进行分组的方法。您可以从const
到ADC_CH_0
声明七个ADC_CH_6
,但由于它们都是相关的,因此最好在此使用enum
(每个enum
常量为默认情况下增加1)。
稍后您可以使用类型adc_channel_t
来声明变量,并保证范围在声明的枚举常量范围内。
答案 3 :(得分:0)
我首选的执行方法如下:
typedef enum powerState_tag {
PS_OFF,
PS_ON
} powerState_te;
这可以在一个表达式中执行多项操作。
出于某些代码解析器/编辑器的目的,我通常添加pwerState_tag来将枚举显示为未命名。我添加后缀以指示_tag是枚举的名称,而_te是类型化的枚举。为了对称起见,我在_tag和_te中都重复了该名称。这些不是标准化的命名约定,除非您的编码标准另有规定,否则可以将其命名为任何名称。 Barr Group拥有一个在线标准,在很多工作中我都曾提到过该标准,并且相当不错。他们不使用_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,而不指定它是枚举,而是像#define一样使用ADC_CH_4。
uint8_t getAdcVal(uint8_t channel); // A
uint8_t getAdcVal(adc_channel_t channel); //B
尽管当用户使用有效范围时A可以正常运行,但是编译器没有像在B时那样验证其在枚举时的范围内。