为什么#define 没有在 child 类 中正确定义?
Why is #define not properly defined in child classes?
我在基础 classes 头文件中有一个定义。在派生的 class 中使用定义是不可能的:
Plugin.h
#ifndef PLUGIN_H
#define PLUGIN_H
#include "../config.h"
#ifdef DEBUG
#define DEBUG_PLUGIN(...) ets_printf( __VA_ARGS__ )
#else
#define DEBUG_PLUGIN(...)
#endif
class Plugin {
public:
Plugin();
...
简单Plugin.h
#ifndef SIMPLE_PLUGIN_H
#define SIMPLE_PLUGIN_H
#include "Plugin.h"
class SimplePlugin : public Plugin {
public:
SimplePlugin();
...
SimplePlugin.cpp
#include "SimplePlugin.h"
SimplePlugin::SimplePlugin() : _devices() {
DEBUG_PLUGIN("[SimplePlugin]\n"); // <-- not printed
}
config.h
已定义 DEBUG
。你能强调预处理器的魔力吗?
更新
这些评论让我走上了正轨。宏扩展当然不依赖于 class 层次结构,实际上根本不依赖于编译器,而是依赖于预处理器。宏已定义,由预处理器扩展并执行,否则我们会看到编译错误。
最后发现 Arduino/esp8266 ets_printf
功能需要额外的硬件配置,否则只会工作不可靠。这种不可靠的行为让它看起来好像只是根据 file/class 层次结构中的位置调用它。
是的,您应该阅读更多关于预定义宏中的 C/C++ preprocessor (both C & C++ share the same preprocessor, with some differences 的内容)。它仅以文本方式运行。它没有类型(例如 class
)或范围的概念。
您可以使用如下命令行获得 SimplePlugin.cpp
的预处理形式:
g++ -C -E SimplePlugin.cpp > SimplePlugin.ii
(您可能需要添加一些额外的 -D
symbol 和 -I
directory 在 -C
之前,与您的编译命令完全相同)
然后,使用您的编辑器或寻呼机查看生成的 SimplePlugin.ii
文件(来自 SimplePlugin.cpp
... 的预处理表格)。
您甚至可以使用
删除行信息(由预处理器在以#
开头的行中发出)
g++ -C -E SimplePlugin.cpp | grep -v '^#' > SimplePlugin.nolines.ii
然后您可以 运行 g++ -c -Wall SimplePlugin.nolines.ii
,诊断将参考预处理文件 SimplePlugin.nolines.ii
,而不是原始的未预处理文件 SimplePlugin.cpp
另请阅读 GNU cpp
的文档
(我猜你使用 GCC;请根据你的编译器套件调整我的答案;我什至猜测你的错误可能与预处理无关)
明显可能的解释是
ets_printf()
- 即 non-standard,而你没有描述 - 并不像你认为的那样工作。例如,如果定义了 DEBUG
,它本身可能是一个定义为不执行任何操作的宏。
DEBUG
实际上并未在您的 config.h
中定义。某处的拼写错误很容易意味着正在定义其他宏,而不是您认为的宏。
- header 实际上可能定义了
DEBUG
,但预处理器随后遇到了 #undef DEBUG
。这可能在同一个 header、不同的 header 中,甚至在您的包含源文件中。
问题不太可能与 类 或构造函数的定义有关。预处理器不遵循作用域规则。
我在基础 classes 头文件中有一个定义。在派生的 class 中使用定义是不可能的:
Plugin.h
#ifndef PLUGIN_H
#define PLUGIN_H
#include "../config.h"
#ifdef DEBUG
#define DEBUG_PLUGIN(...) ets_printf( __VA_ARGS__ )
#else
#define DEBUG_PLUGIN(...)
#endif
class Plugin {
public:
Plugin();
...
简单Plugin.h
#ifndef SIMPLE_PLUGIN_H
#define SIMPLE_PLUGIN_H
#include "Plugin.h"
class SimplePlugin : public Plugin {
public:
SimplePlugin();
...
SimplePlugin.cpp
#include "SimplePlugin.h"
SimplePlugin::SimplePlugin() : _devices() {
DEBUG_PLUGIN("[SimplePlugin]\n"); // <-- not printed
}
config.h
已定义 DEBUG
。你能强调预处理器的魔力吗?
更新
这些评论让我走上了正轨。宏扩展当然不依赖于 class 层次结构,实际上根本不依赖于编译器,而是依赖于预处理器。宏已定义,由预处理器扩展并执行,否则我们会看到编译错误。
最后发现 Arduino/esp8266 ets_printf
功能需要额外的硬件配置,否则只会工作不可靠。这种不可靠的行为让它看起来好像只是根据 file/class 层次结构中的位置调用它。
是的,您应该阅读更多关于预定义宏中的 C/C++ preprocessor (both C & C++ share the same preprocessor, with some differences 的内容)。它仅以文本方式运行。它没有类型(例如 class
)或范围的概念。
您可以使用如下命令行获得 SimplePlugin.cpp
的预处理形式:
g++ -C -E SimplePlugin.cpp > SimplePlugin.ii
(您可能需要添加一些额外的 -D
symbol 和 -I
directory 在 -C
之前,与您的编译命令完全相同)
然后,使用您的编辑器或寻呼机查看生成的 SimplePlugin.ii
文件(来自 SimplePlugin.cpp
... 的预处理表格)。
您甚至可以使用
删除行信息(由预处理器在以#
开头的行中发出)
g++ -C -E SimplePlugin.cpp | grep -v '^#' > SimplePlugin.nolines.ii
然后您可以 运行 g++ -c -Wall SimplePlugin.nolines.ii
,诊断将参考预处理文件 SimplePlugin.nolines.ii
,而不是原始的未预处理文件 SimplePlugin.cpp
另请阅读 GNU cpp
的文档(我猜你使用 GCC;请根据你的编译器套件调整我的答案;我什至猜测你的错误可能与预处理无关)
明显可能的解释是
ets_printf()
- 即 non-standard,而你没有描述 - 并不像你认为的那样工作。例如,如果定义了DEBUG
,它本身可能是一个定义为不执行任何操作的宏。DEBUG
实际上并未在您的config.h
中定义。某处的拼写错误很容易意味着正在定义其他宏,而不是您认为的宏。- header 实际上可能定义了
DEBUG
,但预处理器随后遇到了#undef DEBUG
。这可能在同一个 header、不同的 header 中,甚至在您的包含源文件中。
问题不太可能与 类 或构造函数的定义有关。预处理器不遵循作用域规则。