【问题标题】:What constitutes a declaration in case of an enum?在枚举的情况下,什么构成声明?
【发布时间】:2017-01-15 23:10:07
【问题描述】:

编辑#1:添加最小重复,见下文:

背景

我正在尝试将我的代码分割成多个 .cpp 文件,所有这些文件都应该可以访问 enum 类型,我认为我是在头文件中声明,然后包括在许多cpp 文件中。

但是,当我尝试将它们链接在一起时,我会收到 multiple definitionnot defined 错误。我认为这源于我对 declaration 是什么以及 definition 是什么的可能的误解。我的意思是我很清楚这个(reference)

  • 当编译器为变量分配存储空间时,就定义了一个变量。
  • 当编译器被告知变量存在时声明变量(这是它的类型);那时它不会为变量分配存储空间。

问题

如果我的main.h 文件中有这个,这显然只是一个声明,不是吗?

#1

enum operation_status {
    PRE_START,
    RUNNING,
    PAUSED
};

那么这个呢?这是声明还是定义?

#2

operation_status op_status;

我认为这确实是一个声明,与之相关的定义是

#3

op_status = PRE_START;

提前感谢您的回答!

可重现的例子:

Main.h

enum operation_status {
    PRE_START,
    RUNNING,
    PAUSED
};

//error given by this: 'multiple definition of op_status'
operation_status op_status;

//error given by this: 'undefined reference to op_status'
extern operation_status op_status;

void changeStatus();

Main.cpp

#include <Arduino.h>
#include <main.h>

void setup() {
    op_status = PRE_START;
}

void loop() {
    ;
}

Change.cpp

#include <main.h>

void changeStatus() {
    op_status = RUNNING;
}

解决此问题的最佳解决方案是什么?谢谢!

【问题讨论】:

  • 为什么不分享一个最小的例子来展示你正在经历的令人不安的行为呢?这也可能有助于en.wikipedia.org/wiki/One_Definition_Rule
  • 添加了示例。抱歉,我认为解释很清楚。
  • 第一个 sn-p 既不声明也不定义变量。您将在每本 C++ 书籍中找到详细信息(尽管 Arduino 并不完全是 C++)。
  • 该问题是通用 C++ 问题,不需要标记 [embedded] 或 [arduino]

标签: c++ enums arduino embedded


【解决方案1】:

首先,每个定义都是一个声明;定义是一种特殊的声明。

enum operation_status {
    PRE_START,
    RUNNING,
    PAUSED
};

在技术上是一个定义——它定义了operation_status的类型。但它是一种允许出现在多个编译单元中的排序定义(只要它每次都具有相同的内容和含义),因此头文件通常是它的正确位置。

operation_status op_status;

实际上是一个定义,尽管它没有初始化器。为了使它不是一个定义,你需要 extern 关键字:

extern operation_status op_status;

要使用的定义属于一个源文件,并且可以选择有一个初始化程序。

operation_status op_status = PRE_START;

最后,

op_status = PRE_START;

根本不是声明。这是一个语句,并且只在函数定义中有效。

【讨论】:

  • 你的解释很清楚,谢谢!将extern 关键字添加到main.h,然后将operation_status op_status 添加到main.cpp 确实可以解决问题。这是伟大的。不太好,这正是我想要避免的,即我想尽可能地保留在main.h 中,以避免main.cpp 中的混乱。必须在 main.h 中使用 extern 声明,然后在 main.cpp 中使用未初始化的定义会使事情变得更加混乱。
  • 我感到困惑的是:int x 总是被视为一个声明,只有写int x = 0 才是一个定义。那为什么operation_status op_status 是一个定义 而不仅仅是一个声明 如果我不初始化它呢?这是因为operation_status 有它的可能值列表吗?
  • 第一个不是定义。它是一个类型声明
  • int x; 也是一个定义。
  • @Olaf:参见标准 3.1/2。在示例中,enum { up, down }; 称为定义。
【解决方案2】:

我正在尝试将我的代码分割成多个 .cpp 文件,所有这些文件都应该可以访问一个枚举类型,我认为我是在头文件中声明的,然后包含在多个 cpp 文件中。

您不能前向声明没有指定基础类型的无范围枚举(标准不允许这样做)。这是 c++11 之前的一种枚举。对于此类枚举,Standard 不会对编译器强制执行任何默认的底层类型,因此如果您在枚举中仅指定几个值,它可以使用 char,或者如果您有一些较大的值,则可以使用 short 或 int。但这只有在你定义它时才会知道。

如果你想声明一个无作用域的枚举,那么你必须指定它的底层类型。从 c++11 开始这是可能的:

// forward declare (in header file .h)
enum operation_status : int;


// define (in implementation file .cpp)
enum operation_status : int {
    PRE_START,
    RUNNING,
    PAUSED
};

但您也可以继续使用新的作用域枚举,它们的基础类型默认为 int:

// forward declare
enum class operation_status;


// define
enum class operation_status {
    PRE_START,
    RUNNING,
    PAUSED
};

[编辑]

您的问题:

enum operation_status {
    PRE_START,
    RUNNING,
    PAUSED
};
If I have this in my main.h file, this is clearly just a declaration, isn't it?

这既是声明又是定义,我上面的回答对此更深入。

操作状态操作状态;

这就是定义。你不需要初始化它,让它成为一个定义。

【讨论】:

  • 谢谢,您的回答提供了丰富的信息。 Arduino 环境使用了一种奇怪的 C/C++ 混合。在 C 中,你所谓的 unscoped 很好,它始终是 int 类型。但老实说,我不知道我应该在这里使用 C 还是 C++ 约定。永远不清楚我站在 C/C++ 围栏的哪一边。
猜你喜欢
  • 2020-09-12
  • 1970-01-01
  • 2014-06-20
  • 1970-01-01
  • 2016-03-31
  • 1970-01-01
  • 1970-01-01
  • 2012-12-02
  • 1970-01-01
相关资源
最近更新 更多