extern的使用和防止重复定义
Use of extern and preventing duplicate definitions
我正在用我正在使用的实际文件重写这个(但是被大大剥离了。我需要在半睡半醒的时候停止发帖。)
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,然后将它们放入带有 extern 的 test.cpp 和 test2.cpp 给我几乎相同的错误。
您想要在 header 中包含 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;
当你在上面贴上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;
in test.hpp 承诺 u8x8
已经或将在其他地方定义并且可以安全使用。下一步信守承诺。 In test.cpp XOR test2.cpp (两者之一,而不是两者)添加
U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/SCL, /* data=*/SDA, /* reset=*/OLED_RESET);
对 button
和 encoder
做同样的事情。
多读书
和 C,不是 C++,但 C 和 C++ 在这里足够接近,因此这个较长的讨论很有用:How do I use extern to share variables between source files?
我正在用我正在使用的实际文件重写这个(但是被大大剥离了。我需要在半睡半醒的时候停止发帖。)
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,然后将它们放入带有 extern 的 test.cpp 和 test2.cpp 给我几乎相同的错误。
您想要在 header 中包含 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;
当你在上面贴上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;
in test.hpp 承诺 u8x8
已经或将在其他地方定义并且可以安全使用。下一步信守承诺。 In test.cpp XOR test2.cpp (两者之一,而不是两者)添加
U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/SCL, /* data=*/SDA, /* reset=*/OLED_RESET);
对 button
和 encoder
做同样的事情。
多读书
和 C,不是 C++,但 C 和 C++ 在这里足够接近,因此这个较长的讨论很有用:How do I use extern to share variables between source files?