Неопределенная ошибка ссылки на статический элемент данных constexpr

#c #c 11 #arduino #constexpr #undefined-reference

#c #c 11 #arduino #constexpr #неопределенная ссылка

Вопрос:

Я очень смущен тем, что здесь не так. Я получаю неопределенную ошибку ссылки на массив, который я определил так же, как и два других, которые не выдают ошибок в другом месте кода.

 undefined reference to `shift7seg::numbers'
 

shift7seg.cpp код, показывающий другую функцию, использующую аналогичные используемые массивы

 uint8_t shift7seg::convert_char(const charamp; OGchar){
    uint8_t converted;
    switch (OGchar){
        case 'A':
            converted = capital[0];
            break;
        case 'h':
            converted = lower[3];
            break;
    //more cases removed for posting
    }
    return converted;
}

uint8_t shift7seg::convert_num(const uint8_tamp; OGnum){
   uint8_t converted;

   if(OGnum<10){
       converted = numbers[OGnum];
   }
   else{
       converted = blank;
   }
   return converted;
}
 

shift7seg.h, показывающий определения используемых массивов

 class shift7seg{
public:
//constructor, choose pins to use as well as display size
    shift7seg(const uint8_t _dataPin,
              const uint8_t _latchPin,
              const uint8_t _clkPin,
              const uint8_t _num_digits);

    static constexpr uint8_t numbers[10] =               // 7 segment values for decimals 0..9
    {
    //TRUTH TABLE    |   0 = segment on
    //ABCDEFGH       |   1 = segment off
    B00000011,  //0  |        A
    B10011111,  //1  |      -----
    B00100101,  //2  |   F |     | B
    B00001101,  //3  |     |  G  |
    B10011001,  //4  |      -----
    B01001001,  //5  |   E |     | C
    B01000001,  //6  |     |     |
    B00011111,  //7  |      -----
    B00000001,  //8  |        D
    B00011001       //9  |
    };

    static constexpr uint8_t capital[13] =
    {
    B00010001,  //A or R, 0
    B00000001,  //B 1
    B01100011,  //C 2
    B00000011,  //D or O, 3
    B01100001,  //E 4
    B01110001,  //F 5
    B01000001,  //G 6
    B10010001,  //H 7
    B10000111,  //J 8
    B11100011,  //L 9
    B00110001,  //P 10
    B01001001,  //S 11
    B10000011  //U or V, 12
    };

    static constexpr uint8_t lower[9] =
    {
    B11000001,  //b 0
    B11100101,  //c 1
    B10000101,  //d 2
    B11010001,  //h 3
    B10011111,  //l 4
    B11010101,  //n 5
    B11000101,  //o 6
    B11110101,  //r 7
    B11000111   //u or v, 8
    };
 

Диалект — C 11
Я ни за что на свете не смогу понять, что я сделал не так. Разговор с резиновой уткой пока ничего не дал.

Больше кода ошибки здесь .

 more undefined references to `shift7seg::numbers' follow
collect2.exe: error: ld returned 1 exit status
exit status 1
 

Комментарии:

1. Разве вам не нужно определять статические переменные-члены вне самого определения класса?

2. Этот код должен быть абсолютно законным в C 17. Каков ваш диалект C ?

3. Похоже, что этот код компилируется на c 11, то есть это единственный компилятор, который я могу использовать в данном случае. как бы это выглядело, определяя статические переменные-члены в другом месте? Было бы это в моем driver.cpp и присваивать значения как глобальной переменной?

4. За исключением «constexpr» (C 11 или выше), я не вижу никаких причин, по которым это не должно компилироваться и связываться с ЛЮБОЙ версией C ! Вопрос: Возможно, один или другой из ваших объектных файлов, ссылающихся на «shift7seg», не был скомпилирован с C 11?

5. Я не знаком с этим типом ошибок, но я попытался скомпилировать его. Я получил одну дополнительную ошибку: /usr/bin/ld: /tmp/cckpICDV.o: warning: relocation against '_ZN9shift7seg7numbersE' in read-only section '.text' . Код становится способным к компиляции OGnum , когда вы меняете numbers доступ к массиву на некоторую константу like 2 , однако он также компилируется при переходе на C 17.

Ответ №1:

Где-то в вашем коде вы используете ODR numbers , но у вас нет определения для этого.

Вот простая версия вашей проблемы (wandbox):

 #include <iostream>
#include <cstdint>

class shift7seg {
  public:
   static constexpr std::uint8_t numbers[10] = {};
};

int main() {
  // taking the address is ODR-use
  std::cout << amp;shift7seg::numbers[0] << 'n';
}
 

Возможные решения

  1. скомпилируйте с -std=c 17 помощью (или более поздней версии), где все static constexpr элементы данных являются неявными inline и не требуют внесистемных определений
  2. Добавьте нестандартное определение в свой файл реализации (shift7seg.cpp ) вот так (коробка для волшебных палочек):
 constexpr std::uint8_t shift7seg::numbers[10];
 

Комментарии:

1. Похоже, что это проблема, добавление нестандартного определения устранило эту ошибку и привело к появлению других. отладка продолжается, спасибо

Ответ №2:

Прежде всего, я думаю, что префикс находится 0B в этих двоичных литералах, а не B . Во-вторых, вам нужен c 17 для его компиляции из-за статического содержимого constexpr.

Цитата

Если статический элемент данных объявлен constexpr, он неявно является встроенным и не нуждается в повторном объявлении в области пространства имен. Это повторное объявление без инициализатора (ранее требовалось, как показано выше) по-прежнему разрешено, но устарело.

из https://en.cppreference.com/w/cpp/language/static

Комментарии:

1. это весь код для arduino, поэтому правильный двоичный буквальный тег — B я посмотрю, смогу ли я заставить его работать без constexpr