Arduino IDE 中自定义库 class 的 .h 文件编译错误的原因是什么

What is reason for compile errors from .h file of custom library class in Arduino IDE

我正在使用 Energia(Arduino 的一个分支)为机器人开发程序。我决定创建一个由单个 class 组成的库来处理位置和距离计算。

当我尝试使用 class 时,我看到了我不理解的编译器错误。

这是我的 .h 文件:

#ifndef Position
#define Position
#include "Energia.h"
class Position
{
    public:
        Position(int PinEcho, int PinTrig);
        float getDistance(char* Distance);
        float getDistanceMoy(int Nombre,char* unite);
    private:
        int _pinEcho;
        int _pinTrig;

};
#endif

.cpp 文件包含:

#include "Energia.h" //Arduino.h if we are using Arduino
#include "Position.h"

Position::Position(int pinEcho,int pinTrig)
{
    pinMode(pinEcho, OUTPUT);
    pinMode(pinTrig, INPUT);
    digitalWrite(pinTrigger, LOW);
    int _pinEcho = pinEcho;
    int _pinTrig = pinTrig;
    const unsigned long MEASURE_TIMEOUT = 25000UL;
    const float SOUND_SPEED = 340 / 1000;
}

float Position::getDistance(char* mode){
    digitalWrite(pinTrigger, LOW);
    digitalWrite(pinTrigger, HIGH);
    delayMicroseconds(10);
    digitalWrite(pinTrigger, LOW);
    long mesure = pulseIn(pinEcho,HIGH,MEASURE_TIMEOUT);
    float distance = mesure / 2 * SOUND_SPEED;
    if(mode =="cm") distance = distance / 10;
    if(mode =="dm") distance = distance / 100;
    if(mode == "m") distance = distance / 1000;
    return distance;
}

float Position::getDistanceMoy(int maxi,char* mode){
    int i=0, j=0;
    int distMoy = 0;
    while(i != maxi ){
        digitalWrite(pinTrigger, LOW);
        digitalWrite(pinTrigger, HIGH);
        delayMicroseconds(10);
        digitalWrite(pinTrigger, LOW);
        long mesure = pulseIn(pinEcho,HIGH,MEASURE_TIMEOUT);
        float distance = mesure / 2 * SOUND_SPEED;
        if(distance != 0){
            distMoy += distance;
            j++;
        }
        i++;
    }
    distMoy = distMoy/j;
    if(mode =="cm") distMoy = distMoy / 10;
    if(mode =="dm") distMoy = distMoy / 100;
    if(mode == "m") distMoy = distMoy / 1000;
    return distMoy;
}

然后我用#include <Position.h>在Arduino上导入库然后初始化它:

Position position(Variable1,Variable2);

但是当我想使用它和 Energia(或 Arduino)时,我得到这些错误:

In file included from C:\Users\alex9\Documents\Energia\sketch_may10a\sketch_may10a.ino:1:0:
C:\Users\alex9\Documents\Energia\libraries\Position/Position.h:15:18: error: expected unqualified-id before 'int'
         Position(int PinEcho, int PinTrig);
                  ^
C:\Users\alex9\Documents\Energia\libraries\Position/Position.h:15:18: error: expected ')' before 'int'
C:\Users\alex9\Documents\Energia\libraries\Position/Position.h:13:1: error: an anonymous struct cannot have function members
 {
 ^
C:\Users\alex9\Documents\Energia\libraries\Position/Position.h:22:1: error: abstract declarator '<anonymous class>' used as declaration
 };
 ^
sketch_may10a:8: error: expected constructor, destructor, or type conversion before '(' token
 Position position(PinEcho,PinTrig);
                  ^
exit status 1 expected constructor, destructor, or type conversion before '(' token

我不明白这些错误消息,也不知道我需要修复什么。有人可以帮助我吗?

在您的 .h 文件中,您有以下文本行是预处理器命令:

  • 检查是否定义了预处理器宏 "Position"
  • 如果未定义则将其定义为空或无文本

一旦预处理器为宏定义了这个宏 "Position" 然后当预处理器继续进行源文本处理时,它所做的其中一件事就是每次找到标记 "Position" 它将用其定义的值替换该标记,在本例中为空字符串。

#ifndef Position
#define Position

使用Preprocessor时一定要记住,它是一个额外的处理步骤,与编译无关。这是一个纯文本处理步骤,用于在将源文本输入编译器之前修改源文本,这是一个完全独立的步骤。

您可以通过 运行 预处理器本身检查发生了什么,并查看生成的输出文件。虽然通常是编译器开关,但编译器之间的完成方式会有所不同。

将预处理器保护程序放入 .h 文件的典型方法是执行类似此示例的操作。这个用于包含文件保护的预处理器宏由包含文件的名称、字母 "H" 和单词 "included" 组成,各个部分用下划线连接:

#ifndef POSITION_H_INCLUDED
#define POSITION_H_INCLUDED

通过使用此宏名称,宏名称与某些变量或 class 或结构 name/label 或源文件中的其他文本标记之间发生冲突的可能性会大大降低。

此命名约定可以为您做几件事。

首先它全部使用大写,这是预处理器宏名称的实际标准。

其次,它很好地描述了这个宏名称的意图。

第三,其他一些文本标记相同的可能性相当小,因此出现像您 运行 这样的错误的可能性很小。

大量源代码的命名方法

但是对于一个大型项目,如数十万行代码和数千个文件,不同库中的不同包含文件可能使用相同的名称。同样的问题是为什么 namespace 概念是用 C++ 发明的。

因此,使用添加到宏名称的一些额外文本的更复杂的名称会增加宏名称唯一的可能性。一种方法是将库名称或制造商名称添加到宏名称中。

#ifndef POSITION_H_INCLUDED_POSITION_LIB_MICHAUD
#define POSITION_H_INCLUDED_POSITION_LIB_MICHAUD

一种简单的方法是将日期和时间添加到宏名称中,如下所示:

#ifndef POSITION_H_INCLUDED_20180517_1021_00
#define POSITION_H_INCLUDED_20180517_1021_00

有些 IDE 会为您做类似的事情,作为为 class 生成源代码的一部分,诸如此类。这是一个来自较旧的 Visual Studio C++ IDE 的示例,它生成了一个 MFC class 包含文件。这有点矫枉过正,因为它似乎 IDE 生成了一个非常独特的 GUID,并使用它来创建 99.999999999% 可能是唯一的预处理器宏名称或标识符。请注意,作为生成此宏名称的一部分,IDE 使用了包含文件的名称、字母 "H" 和单词 "included" 以及 GUID。

#if !defined(AFX_OPOSCASHDRAWER_H__86921069_045D_4880_A41A_5A18F0E5FABD__INCLUDED_)
#define AFX_OPOSCASHDRAWER_H__86921069_045D_4880_A41A_5A18F0E5FABD__INCLUDED_

另请注意,IDE 生成的预处理器指令正在使用 defined() 运算符。这允许您通过预处理器的 #if 指令使用更复杂的逻辑操作。

有关预处理器的更多详细信息,请参阅此 Wikipedia article, C Preprocessor。 material 应该也适用于预处理器的大多数 C++ 版本。

你不应该像命名定义

一样命名Class

定义就像一个别名,因此,您的 Class 名称被设置为定义值,在您的例子中为空字符串。