0

Trying to create a small test, I had met a problem

#include "stdafx.h"
#include "CppUnitTest.h"
#include "CppUnitTestAssert.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace SprintfTestNamespace
{       
    TEST_CLASS(SprintfTest)
    {
    public:
        static char output[100];
        static const char * expected;

        TEST_METHOD_INITIALIZE(SprintfTestInit)
        {
            memset(output, 0xaa, sizeof output);
            SprintfTest::expected = "";
        }
        static void expect(const char * s)
        {
            expected = s;
        }
        static void given(int charsWritten)
        {
            Assert::AreEqual((int)strlen(expected), charsWritten,
                L"result string length ");
            Assert::AreEqual(expected, output, false,
                L"result string content ");
            Assert::AreEqual((char)0xaa, output[strlen(expected) + 1],
                L"meaning of the first outer char after string");

        }

        TEST_METHOD(NoFormatOperations)
        {
            expect("hey");
            given(sprintf(output, "hey"));
        }
        TEST_METHOD(InsertString)
        {
            expect("Hello World\n");
            given(sprintf(output, "Hello %s\n", "World"));
        }
    };
    char SprintfTest::output[100];      // notice these two lines!
    const char* SprintfTest::expected;
}

If I remove the two marked lines at the end, I am getting the errors LNK2001:

unresolved external symbol "public: static char * SprintfTestNamespace::SprintfTest::output" (?output@SprintfTest@SprintfTestNamespace@@2PADA)

If I have them in place, everything works OK, it builds and links and tests. But why have I to define the class variables out of the class if I use them only inside it?

Gangnus
  • 24,044
  • 16
  • 90
  • 149
  • And defining static members in header this way may violate One Definition Rule (i.e., if header is included in multiple source files). – Mahesh Oct 14 '15 at 19:01

1 Answers1

2

You are not declaring them out of class. You are defining them out of class. In C++ an object used as lvalue needs a definition, which essentially reserves storage (memory) for that object. For static class members, you reserve that memory by defining such objects out of class.

What you have inside your class are mere non-defining declarations of these static members. Providing definitions for these declarations is your responsibility. When you forget to define something you declared, you get that "unresolved external symbol ..." error from the linker, which is exactly what happened in your case.

Note that in order to satisfy the One Definition Rule these definitions should typically go to a single implementation file (.cpp file). You should not place such definitions into header files.

The only exception from the above in C++ are static members of certain types that are not used as lvalues anywhere in the code, thus eliminating the need to allocate memory for such members.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765