【问题标题】:Use of extern and preventing duplicate definitions使用外部和防止重复定义
【发布时间】:2019-04-01 23:28:59
【问题描述】:

我正在用我正在使用的实际文件重新措辞(但被大大剥夺了。当我半睡半醒时,我需要退出发布。)

Test.hpp 内容为:

/*
 * test.hpp
 *
 *  Created on: Apr 1, 2019
 *      Author: Mike
 */

#ifndef INCLUDE_TEST_HPP_
#define INCLUDE_TEST_HPP_
#include <U8x8lib.h>



#define R1 13
#define RGROUND 12  //the rotary switch is connected via header pins on the board for development.
#define R2 14
#define SWITCH 27
#define SCL 15
#define SDA 4
#define OLED_RESET 16


#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

#include <RotaryEncoder.h>
#include "OneButton.h"


U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/SCL, /* data=*/SDA, /* reset=*/OLED_RESET);
OneButton button(SWITCH, true);
RotaryEncoder encoder(R1, R2);

void testFunc();

#endif /* INCLUDE_TEST_HPP_ */
/*      end of test.hpp"   */

test.cpp 读作:

#include <Arduino.h>
#include "test.hpp"

#include <U8x8lib.h>
#include <RotaryEncoder.h>
#include "OneButton.h"

void setup() {
    u8x8.begin();
    u8x8.clearDisplay();
//  encoder.begin();    //there's no begin functions for either of these.
//  button.begin();
}

void loop() {
    encoder.tick();
    button.tick();
    u8x8.print("starting loop");
    testFunc();
}

test2.cpp 读取

/*
 * test2.cpp
 *
 *  Created on: Apr 1, 2019
 *      Author: Mike
 */

#include "test.hpp";

void testFunc(){
    encoder.getPosition();
    //do some other stuff.
}

编译上面给出了以下错误:

Linking .pioenvs\uno\firmware.elf
.pioenvs\uno\src\test2.cpp.o (symbol from plugin): In function `u8x8':
(.text+0x0): multiple definition of `u8x8'
.pioenvs\uno\src\test.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pioenvs\uno\src\test2.cpp.o (symbol from plugin): In function `u8x8':
(.text+0x0): multiple definition of `button'
.pioenvs\uno\src\test.cpp.o (symbol from plugin):(.text+0x0): first defined here
.pioenvs\uno\src\test2.cpp.o (symbol from plugin): In function `u8x8':
(.text+0x0): multiple definition of `encoder'
.pioenvs\uno\src\test.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
*** [.pioenvs\uno\firmware.elf] Error 1

如果我尝试用 extern 添加三行

extern U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/SCL, /* data=*/SDA, /* reset=*/OLED_RESET);
extern OneButton button(SWITCH, true);
extern RotaryEncoder encoder(R1, R2);

到 test.hpp 和 test2.cpp 文件,然后到 test.cpp 没有外部,我得到这个错误:

In file included from src\test.cpp:2:0:
include/test.hpp:34:46: warning: 'u8x8' initialized and declared 'extern'
extern U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/SCL, /* data=*/SDA, /* reset=*/OLED_RESET);
^
include/test.hpp:35:24: warning: 'button' initialized and declared 'extern'
extern OneButton button(SWITCH, true);
^
include/test.hpp:36:29: warning: 'encoder' initialized and declared 'extern'
extern RotaryEncoder encoder(R1, R2);
^
src\test.cpp:8:39: error: redefinition of 'U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8'
U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/SCL, /* data=*/SDA, /* reset=*/OLED_RESET);
^
In file included from src\test.cpp:2:0:
include/test.hpp:34:42: note: 'U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8' previously declared here
extern U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/SCL, /* data=*/SDA, /* reset=*/OLED_RESET);
^
src\test.cpp:9:17: error: redefinition of 'OneButton button'
OneButton button(SWITCH, true);
^
In file included from src\test.cpp:2:0:
include/test.hpp:35:18: note: 'OneButton button' previously declared here
extern OneButton button(SWITCH, true);
^
src\test.cpp:10:22: error: redefinition of 'RotaryEncoder encoder'
RotaryEncoder encoder(R1, R2);
^
In file included from src\test.cpp:2:0:
include/test.hpp:36:22: note: 'RotaryEncoder encoder' previously declared here
extern RotaryEncoder encoder(R1, R2);
^
In file included from src\test2.cpp:8:0:
include/test.hpp:34:46: warning: 'u8x8' initialized and declared 'extern'
extern U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/SCL, /* data=*/SDA, /* reset=*/OLED_RESET);
^
include/test.hpp:35:24: warning: 'button' initialized and declared 'extern'
extern OneButton button(SWITCH, true);
^
include/test.hpp:36:29: warning: 'encoder' initialized and declared 'extern'
extern RotaryEncoder encoder(R1, R2);
^
src\test2.cpp:10:46: warning: 'u8x8' initialized and declared 'extern'
extern U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/SCL, /* data=*/SDA, /* reset=*/OLED_RESET);
^
src\test2.cpp:10:46: error: redefinition of 'U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8'
In file included from src\test2.cpp:8:0:
include/test.hpp:34:42: note: 'U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8' previously declared here
extern U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/SCL, /* data=*/SDA, /* reset=*/OLED_RESET);
^
src\test2.cpp:11:24: warning: 'button' initialized and declared 'extern'
extern OneButton button(SWITCH, true);
^
src\test2.cpp:11:24: error: redefinition of 'OneButton button'
In file included from src\test2.cpp:8:0:
include/test.hpp:35:18: note: 'OneButton button' previously declared here
extern OneButton button(SWITCH, true);
^
src\test2.cpp:12:29: warning: 'encoder' initialized and declared 'extern'
extern RotaryEncoder encoder(R1, R2);
^
src\test2.cpp:12:29: error: redefinition of 'RotaryEncoder encoder'
In file included from src\test2.cpp:8:0:
include/test.hpp:36:22: note: 'RotaryEncoder encoder' previously declared here
extern RotaryEncoder encoder(R1, R2);
^
*** [.pioenvs\uno\src\test.cpp.o] Error 1
*** [.pioenvs\uno\src\test2.cpp.o] Error 1
 [ERROR] Took 3.51 seconds 

将这三个不带 extern 放入 test.hpp,然后将它们放入 test.cpp 和带有 extern 的 test2.cpp 给我几乎相同的错误。

【问题讨论】:

  • 您似乎将foo 声明为一个函数(您确实说过它是一个C 文件,为什么要标记为c++?)。您不能在函数上使用成员访问运算符.
  • 如果您的意思是 foo 是 C++ 类类型的对象,则您需要在头文件中使用 extern,并且在一个 C++ 编译单元中需要一个没有 extern 的定义.如果这些是 C++ 源文件,请修正您的文件名。
  • 这里有个很好的问题,如果你能把它弄清楚。
  • 我仍然不知道foo是一个函数,它接受spameggs类型的两个参数,返回一个Fubar,或者foo是一个类型的变量Fubar,另外两个值被传递给构造函数。你能澄清一下是什么吗?

标签: c++ header extern


【解决方案1】:

您想要一个在标题中带有extern 的声明。只是声明。所以在Test.hpp中

U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/SCL, /* data=*/SDA, /* reset=*/OLED_RESET);

变成

extern U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8;

Obligatory Standard quote

当你把extern贴在上面并离开初始化时,

// bad code! Do not use!
extern U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8( ... );
                                             ^ initialization   

extern 被有效地忽略,你得到一个definition instead of a declaration。编译器可能会警告你,它确实这样做了

include/test.hpp:34:46: warning: 'u8x8' initialized and declared 'extern'

但是,如果您不知道自己在寻找什么,那么该消息将无济于事。无论如何,不​​要忽视警告。他们是编译器,告诉你,虽然某些东西可以编译(它在语法上是正确的),但它可能并不意味着你想要什么或做你想要的(它可能在逻辑上是不正确的)。您可能会发现警告通常包含比导致的实际错误更有用的信息,因此请找出它们的含义并消除它们。

回到话题,

extern U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8;

在 test.hpp 中承诺 u8x8 已经或将要在其他地方定义并且可以安全使用。下一步将信守承诺。在 test.cpp XOR test2.cpp(两者之一,不是两者)添加

U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/SCL, /* data=*/SDA, /* reset=*/OLED_RESET);

buttonencoder 执行相同的操作。

更多阅读

When to use extern in C++

和 C,而不是 C++,但 C 和 C++ 在这里足够接近,因此这个更长的讨论很有用:How do I use extern to share variables between source files?

【讨论】:

  • 谢谢。我实际上已经确定我要自己解决这个问题并进行更多挖掘,并意识到就像“extern int foo = 0”是错误的(我已经在其他地方看到过)使用“extern fooFunction()”也是错误并完全省略 () (不仅仅是让它们为空。)所以一旦我意识到这一点并且我终于可以干净地编译它,我回到这里看看是否有人在这里做出了回应。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-01
  • 1970-01-01
  • 2015-07-18
  • 2015-10-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多