2

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
7
  • Don't you have to define static member variables outside the class definition itself? Commented Dec 9, 2020 at 18:40
  • 1
    This code should be perfectly legal in C++17. What's your C++ dialect? Commented Dec 9, 2020 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? Commented Dec 10, 2020 at 0: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? Commented Dec 10, 2020 at 1: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. Commented Dec 10, 2020 at 2:11

2 Answers 2

3

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];
Sign up to request clarification or add additional context in comments.

1 Comment

Appears this is the issue, adding out-of-line definition has removed that error and brought others. the debugging continues, thank you
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

1 Comment

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.