【问题标题】:typedef enum explanation in cc中的typedef枚举解释
【发布时间】:2015-12-07 11:25:31
【问题描述】:

我正在查看微控制器上 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 是什么意思?

谢谢

【问题讨论】:

  • typedef 只是用来命名一种类型的缩写,因此您不必每次使用时都重新输入整个内容。
  • 使用它来缩写 enum 类型并没有什么特别之处。
  • 您不一定要为 ADC 创建新的数据类型。枚举是一个 int,您可以将其用作一组常量的标识符。从可读性的角度来看,稍后在代码中很明显ADC_CH_0(其值为 0)正好是通道 0。简单地为所述组使用整数是等待发生的灾难。枚举有助于保持整洁。

标签: c typedef


【解决方案1】:

作为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_0ADC_CH_6,这可能是值的有效范围,而不是简单地告诉您使用数字。

【讨论】:

    【解决方案2】:

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

    1. typedef 有什么作用
    2. 为什么 typedef 枚举

    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!
    

    【讨论】:

    • 学究起来,如果你真的想让你的意图更清楚,你的typedef char uint8;应该是typedef unsigned char uint8;typedef char int8;,因为u通常意味着类型是无符号的;)。
    【解决方案3】:

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

    typedef enum 是一种对相关常量进行分组的方法。你可以改为声明七个const,从ADC_CH_0ADC_CH_6,但是因为它们都是相关的,所以最好在这里使用enum(每个enum 常量默认增加1)。

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

    【讨论】:

      【解决方案4】:

      我的首选方法如下:

      typedef enum powerState_tag {
          PS_OFF,
          PS_ON
      } powerState_te;
      

      这在一个表达式中完成了几件事。

      1. 声明枚举 pwerState_tag {PS_OFF, PS_ON}。
      2. 创建 powerState_te 的 typedef。

      我通常添加 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 那样在编译时验证它是否在枚举范围内。

      Barr Group's coding standard

      【讨论】:

        【解决方案5】:

        让我们分别了解typedefenum

        枚举

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

        考虑这个示例代码:

        enum bool{
        FALSE, 
        TRUE
        };
        

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

        1. 枚举在范围内是本地的
        2. 编译器初始化值 注意:所有名称在范围内必须是唯一的,并且只能是整数 常量可以作为名称的值。

        typedef

        考虑我们定义数据类型的示例,现在我们想在代码中使用它。你可以使用它的方式是:

        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);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-04
          • 1970-01-01
          • 2015-01-27
          • 2013-12-23
          • 1970-01-01
          • 2010-10-16
          相关资源
          最近更新 更多