1

I'm very confused as to what is wrong here. I am getting an undefined reference error to an array I have defined the same way as two others which are not throwing errors elsewhere in the code.

undefined reference to `shift7seg::numbers'

shift7seg.cpp code showing other function using similarly defined arrays being used

uint8_t shift7seg::convert_char(const char& 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_t& OGnum){
   uint8_t converted;

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

shift7seg.h showing definitions of arrays being used

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

Dialect is C++11 I cannot for the life of me figure out what I have done wrong. Talking to the rubber duck has done nothing so far.

More of the error code is here.

more undefined references to `shift7seg::numbers' follow
collect2.exe: error: ld returned 1 exit status
exit status 1
Ryan Haining
  • 35,360
  • 15
  • 114
  • 174
Tanner G
  • 13
  • 4
  • Don't you have to define static member variables outside the class definition itself? – Nate Eldredge Dec 09 '20 at 18:40
  • 1
    This code should be perfectly legal in C++17. What's your C++ dialect? – SergeyA Dec 09 '20 at 18:49
  • It appears this code is compiling in c++11, that is the only compiler i can use in this case. what would it look like defining the static member variables elsewhere? Would that be in my driver.cpp and assigning the values like a global variable? – Tanner G Dec 10 '20 at 00:59
  • Except for "constexpr" (C++11 or higher), I don't see any reason this shouldn't compile - and link - on *ANY* version of C++! Q: Perhaps one or another of your object files that reference "shift7seg" *wasn't* compiled with C++11? – paulsm4 Dec 10 '20 at 01:25
  • I'm not familiar with this type of error, but I did try to compile it. I got one additional error: `/usr/bin/ld: /tmp/cckpICDV.o: warning: relocation against '_ZN9shift7seg7numbersE' in read-only section '.text'`. The code becomes compile-able when you change the `OGnum` in the `numbers` array access to some constant like `2`, however it also compiles when you change to C++17. – niets Dec 10 '20 at 02:11
  • @Tanner G - please consider simply removing the "constexpr", and let us know if it resolves the problem. – paulsm4 Dec 10 '20 at 02:56
  • @paulsm4 what do you expect that to do? – Ryan Haining Dec 10 '20 at 03:34

2 Answers2

2

Somewhere in your code you are ODR-using numbers but you don't have a definition for it.

Here's a simple version of your problem (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 << &shift7seg::numbers[0] << '\n';
}

Possible solutions are

  1. compile with -std=c++17 (or later) where all static constexpr data members are implicitly inline and don't need out-of-line definitions

  2. Add an out-of-line definition in your implementation file (shift7seg.cpp) like this (wandbox):

constexpr std::uint8_t shift7seg::numbers[10];
Ryan Haining
  • 35,360
  • 15
  • 114
  • 174
  • 1
    Appears this is the issue, adding out-of-line definition has removed that error and brought others. the debugging continues, thank you – Tanner G Dec 10 '20 at 02:58
0

First of all, I think the prefix is 0B in those binary literals, not B . Second of all, you need c++17 to compile it because of the static constexpr stuff.

quote

If a static data member is declared constexpr, it is implicitly inline and does not need to be redeclared at namespace scope. This redeclaration without an initializer (formerly required as shown above) is still permitted, but is deprecated.

from https://en.cppreference.com/w/cpp/language/static

CS Pei
  • 10,869
  • 1
  • 27
  • 46
  • this is all code for an arduino, so the proper binary literal tag is B i'll see if i can get it working without constexpr – Tanner G Dec 10 '20 at 02:54