0

I have the following classes:

MessageConstants.h:

class MessageConstants
{

public:
    ...
    static const int ErrorDescriptionLength = 256;
...
};

SystemMessage.h:

class EvtError
{
private:
    struct MsgData
    {
        int errorCode;            
        char errorDescription[MessageConstants::ErrorDescriptionLength]; 
    }__attribute__((packed)) msgData;

public:
    EvtError(int errorCode, string errorDescription);
    inline void setErrorDescription(string desc){memcpy(msgData.errorDescription, desc.c_str(),
                min(MessageConstants::ErrorDescriptionLength, (int)desc.length()));}

};

SystemMessage.cpp:

EvtError::EvtError(int errorCode, string errorDesc)
{
    memset(&msgData, '\0', sizeof(msgData));
    msgData.errorCode = errorCode;
    memcpy(msgData.errorDescription, errorDesc.c_str(), min(MessageConstants::ErrorDescriptionLength, (int)errorDesc.length()));
}

I got the following link error on SystemMessage.cpp statement memcpy(msgData.errorDescription, errorDesc.c_str(), min(MessageConstants::ErrorDescriptionLength, (int)errorDesc.length())); :

In function EvtError::EvtError(int, std::string): undefined reference to MessageConstants::ErrorDescriptionLength collect2: error: ld returned 1 exit status make: [link] Error 1

If I replace the MessageConstants::ErrorDescriptionLength with sizeof(msgData.errorDescription), the link error disappear.

My questions:

  1. Why it doesn't complain the MessageConstants::ErrorDescriptionLength in the SystemMessage.h file, where there are two places with it?

  2. How to avoid above link error?

5YrsLaterDBA
  • 33,370
  • 43
  • 136
  • 210
  • This is because const static ints in class definitions is broken because they don't have real addresses, which is required for `std::min`. I'm too tired to explain properly. `min((int)MessageConstants::ErrorDescriptionLength` or `min(+MessageConstants::ErrorDescriptionLength` will fix it by making a temporary copy. Alternatively, take it out of the class as a regular const, perhaps in a namespace. – Neil Kirk Jan 25 '15 at 02:55
  • 1
    @NeilKirk Dude stop posting answers in comments. Either post an answer, or don't. – Barry Jan 25 '15 at 02:57
  • you might want to null-terminate your buffer once you fix the link error – M.M Jan 25 '15 at 02:57
  • @MattMcNabb will "memset(&msgData, '\0', sizeof(msgData));" null-terminate the buffer? – 5YrsLaterDBA Jan 25 '15 at 03:18

2 Answers2

3

The signature of min is:

template <typename T>
const T& min(const T&, const T&);

It takes its inputs by reference - which requires them to have storage. Your constant:

static const int ErrorDescriptionLength = 256;

Does not currently have storage. There are two ways to approach this. First, you can just add storage in your .cpp:

const int MessageConstants::ErrorDescriptionLength;

Second, you can just cast it to an int:

min((int)MessageConstants::ErrorDescriptionLength, (int)errorDesc.length())
 // ^^^^^
Barry
  • 286,269
  • 29
  • 621
  • 977
  • I have tried your first solution. It will cause compile error in SystemMessage.h file: array bound is not an integer constant before ‘]’ token – 5YrsLaterDBA Jan 25 '15 at 03:09
  • @5YrsLaterDBA What? All you added was the one line in the MessageConstants.cpp right? – Barry Jan 25 '15 at 03:16
  • I removed the "= 256" from the MessageConstants.h and then add const int MessageConstants::ErrroDescriptionLength = 256; in MessageConstants.cpp. The gcc compiler will complain then. – 5YrsLaterDBA Jan 25 '15 at 03:32
  • 1
    @5YrsLaterDBA Leave the "= 256" in the header. Everything else has to see that value. – Barry Jan 25 '15 at 03:33
  • tried that. It will cause "duplicate" compile error. – 5YrsLaterDBA Jan 25 '15 at 03:56
  • I mean, the 256 should be ONLY in the header. The only change you should be making is adding the one line I mentioned in my answer to your cpp. The headers should be unchanged – Barry Jan 25 '15 at 04:06
0

Static variable must have a definition outside the class:

const int MessageConstants::ErrorDescriptionLength ;

This should go in exactly one .cpp. file in your project.

Sometimes you can get away without it, but in those cases it is either because the variable was not odr-used, or the program was ill-formed (but ODR violations don't require diagnosis).

M.M
  • 138,810
  • 21
  • 208
  • 365