Использование extern и предотвращение дублирования определений

Я переписываю это на файлы, которые я использовал (но сильно урезанные. И мне нужно прекратить публикацию, когда я в полусне).

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 без extern, я получаю эту ошибку:

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 

Помещение этих трех в test.hpp без extern, а затем их размещение в test.cpp и test2.cpp с extern дает мне почти такую ​​же ошибку.


person Mike Anderson    schedule 01.04.2019    source источник


Ответы (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;

Обязательное стандартное предложение

Когда воткнешь extern и оставишь инициализацию,

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

extern фактически игнорируется, и вы получаете определение вместо объявления. Компилятор может вас предупредить об этом, и он сделал

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);

Сделайте то же самое для button и encoder.

Больше чтения

Когда использовать extern в C ++

и C, а не C ++, но C и C ++ здесь достаточно близки, чтобы это более длинное обсуждение было полезным: Как использовать extern для обмена переменными между исходными файлами?

person user4581301    schedule 02.04.2019
comment
Спасибо. На самом деле я решил, что собираюсь разобраться в этом самостоятельно и еще немного покопаться, и понял, что точно так же, как extern int foo = 0 был неправильным (что я уже видел в другом месте), использование extern fooFunction () также было неправильным и оставить полностью исключите () (а не просто оставьте их пустыми). Итак, как только я понял это и наконец смог правильно скомпилировать, я вернулся сюда, чтобы посмотреть, не ответил ли кто-нибудь здесь. - person Mike Anderson; 02.04.2019