【问题标题】:Building an Array of #define Directives构建 #define 指令数组
【发布时间】:2018-12-18 20:43:16
【问题描述】:

我有一些微控制器代码使用一些头文件,其中 GPIO 引脚定义如下:

#define PA3 GPIO(GPIO_PORTA, 3)

使用 IDE,我可以导航到 GPIO 的实现,我发现:

#define GPIO(port, pin) ((((port)&0x7u) << 5) + ((pin)&0x1Fu))

其中pin定义为:

const uint8_t pin

port 是一个enum,定义为:

enum gpio_port { GPIO_PORTA, GPIO_PORTB, GPIO_PORTC, GPIO_PORTD, GPIO_PORTE }

我想创建一个包含所有 GPIO 定义(PA3PA4 等)的数组,这些定义可以通过串行端口传递的整数进行索引。

我尝试了以下方法:

GPIO knavePinList[] = {PA3, PA4, PA21, PB4, PHY_RESET_PIN, PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, PD8, PD9};

但这显然不起作用,因为GPIO 不是公认的 C 类型,实际上是宏。在尝试构建时,我收到以下错误消息:

unknown type name 'GPIO'

我什至可以声明一个宏数组吗?如果是这样,我将如何记录我正在使用的类型?

谢谢。

【问题讨论】:

    标签: c arrays c-preprocessor


    【解决方案1】:

    #define 语句执行文本替换,它们没有固有类型。正如您所指出的,GPIO 不是有效类型,它是一个似乎用于计算引脚编号/地址的宏(实际上 GPIO 是未定义的,而 GPIO(a,b) 是宏)。

    如果你想存储一个包含许多这样的数组,那么你需要知道它们都计算为什么实际类型。鉴于GPIO 宏返回一个port 和一个pin 值的总和,其中port 是一个枚举,其基础类型是int(从技术上讲,它是一个特定于实现的整数类型 - 请参阅@987654321 @) 和 pinuint8_t,您的数组值的实际类型也将是整数类型 - 具体取决于您的实现和可能值的范围。

    【讨论】:

    • 感谢您的回复,我的新解决方案是创建两个数组 - 一个是 enum gpio_port 类型,一个是 uint8_t 类型 - 然后我自己在代码中调用 GPIO(a,b) 宏。我已经编辑了问题以反映我真正想要做的事情 - 也就是说,创建一个宏数组,而不是 #define 指令数组。
    【解决方案2】:

    您发布的数组完全合法,我认为您尚未对其进行测试。无论如何,最好用一个可测试的例子来询问,(见How to create a Minimal, Complete, and Verifiable example)但是代码:

    GPIO knavePinList[] = {PA3, PA4, PA21, PB4, PHY_RESET_PIN, PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, PD8, PD9};
    

    将生成一个完全合法初始化的整数数组,其中包含您从宏扩展的常量的按位值。尝试使用

    cpp source.c | more
    

    查看数组声明实际上是如何展开的。顺便说一句,您的代码中还有另一个不同的问题...您使用相同的标识符GPIO,来指示GPIO 宏名称和数组元素的类型,所以当宏处理器遇到它时,它看不到任何参数,这不是您拥有#defined 的方式,并且抱怨在根本没有参数的情况下调用了两个参数宏GPIO

    您必须测试您的代码...并发送 1. 您期望的内容...和 ​​2. 您得到的内容...因为错误应该很明显,如果您只是停下来阅读它。

    解决您的问题的方法是将宏 GPIO 重命名为 GPIO_BITS 例如...然后更改所有定义:

    #define GPIO_BITS(port, pin) ((((port)&0x7u) << 5) + ((pin)&0x1Fu))
    
    ...
    
    #define PA3 GPIO_BITS(GPIO_PORTA, 3)
    

    所以遇到数组定义时,不会尝试将类型名扩展为宏。

    【讨论】:

    • 事实上,我已经测试了我的代码。我从编译器收到的错误是unknown type name 'GPIO'。我承认我应该在问题中发布错误消息,但它的要点是“但这显然不起作用,因为 GPIO 不是公认的 C 类型,但实际上是宏”。这就是为什么我问这个问题“我如何记录我正在使用的东西的类型?”。
    • 我尝试使用int knavePinList[15] = {PA3, ... }; 进行编译,效果很好。感谢您指出宏是如何解析的!
    • 好吧,尝试将其声明为int,这可能是本意。用你发布的代码的sn-p,很难说。
    【解决方案3】:

    不,您不能创建这样的宏数组。

    如果要根据输入执行特定宏,则需要使用if-elseswitch 语句。如果输入是一个整数,你可以这样做:

    switch( input )
    {
      case 0: PA3; break;
      case 1: PA4; break;
      case 2: PA21; break;
      ...
     }
    

    【讨论】:

    • 抱歉,这个例子没用......因为PA3(例如)扩展为GPIO(GPIO_PORTA, 3),而是扩展为((((GPIO_PORTA)&amp;0x7u) &lt;&lt; 5) + ((3)&amp;0x1Fu)),这是int类型的常量表达式(评估为常量 3 在这种情况下),所以你的 switch 将忽略 case 语句的结果,最终什么都不提供。问题中显示的数组是完全合法的,因为每个宏都扩展为一个常量表达式,可以用作初始化器。 OP 没有测试他的例子,这就是他在这里问的原因。
    猜你喜欢
    • 2012-07-25
    • 2011-09-11
    • 2021-12-30
    • 1970-01-01
    • 2019-03-25
    • 2021-12-31
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    相关资源
    最近更新 更多