Possible compiler error, local struct requesting static variable in function from template parameter (phew)

Can someone please explain why the following code doesn't work in Visual Studio C ++ 2008/2010 if the marked line is commented out? Is this a compiler error or am I doing something wrong? The code should output a sequence of 10 U, but when the line is removed, it doesn't output anything. The chr variable becomes 0 inside the FilledArray constructor. Thank!

// returns a c-string which contains the char repeated a certain number of times
template<char THE_CHAR>
const char *RepeatChar(unsigned int uiNumber)
{
      // must be static so can be accessed by struct
      static const unsigned int uiMaxSize = 1024;
      static const char chr = THE_CHAR;
      char temp = chr; // comment out this line and it doesn't work

      assert(uiMaxSize > 0);
      assert(uiNumber <= uiMaxSize);

      static const struct FilledArray
      {
            char data[uiMaxSize + 1];

            FilledArray()
            {
                  // fill all but last with the char (space for terminator)
                  fill(data, data + uiMaxSize, chr);
                  data[uiMaxSize] = '\0';
            }

      } sFilledArray;

      // clever bit
      return sFilledArray.data + uiMaxSize - uiNumber;
}

int main()
{
      cout << RepeatChar<'U'>(10) << endl;
}

      

+3


source to share


1 answer


Looks like a compiler error. I changed the code to the following:

#include <iostream>
#include <assert.h>
using namespace std;

// returns a c-string which contains the char repeated a certain number of times
template<char THE_CHAR>
const char *RepeatChar(unsigned int uiNumber)
{
      // must be static so can be accessed by struct
      static const unsigned int uiMaxSize = 1024;
      static const char chr = THE_CHAR;
//      char temp = chr; // comment out this line and it doesn't work

      static const struct FilledArray
      {
            char data[uiMaxSize + 1];

            FilledArray()
            {
              cout << "[" << chr << "]" << endl;
                  fill(data, data + uiMaxSize, chr);
                  data[uiMaxSize] = '\0';
            }

      } sFilledArray;

      return sFilledArray.data + uiMaxSize - uiNumber;
}

int main()
{
      cout << RepeatChar<'U'>(10) << endl;
}

      

Then disassemble the problem area, namely:

cout << "[" << chr << "]" << endl;
fill(data, data + uiMaxSize, chr);
data[uiMaxSize] = '\0';

      

and

            cout << "[" << chr << "]" << endl;
00FA3273  push        offset std::endl (0F9E730h)  
00FA3278  push        offset string "]" (0FFE3C0h)  
00FA327D  push        55h  
00FA327F  push        offset string "[" (0FFE3BCh)  
00FA3284  push        offset std::cout (1011F80h)  
00FA3289  call        std::operator<<<std::char_traits<char> > (0F9EF91h)  
00FA328E  add         esp,8  
00FA3291  push        eax  
00FA3292  call        std::operator<<<std::char_traits<char> > (0F9FA3Bh)  
00FA3297  add         esp,8  
00FA329A  push        eax  
00FA329B  call        std::operator<<<std::char_traits<char> > (0F9EF91h)  
00FA32A0  add         esp,8  
00FA32A3  mov         ecx,eax  
00FA32A5  call        std::basic_ostream<char,std::char_traits<char> >::operator<< (0F9EFD2h)  
                  fill(data, data + uiMaxSize, chr);
00FA32AA  push        offset `RepeatChar<85>'::`2'::chr (0FFE3BAh)  
00FA32AF  mov         eax,dword ptr [this]  
00FA32B2  add         eax,400h  
00FA32B7  push        eax  
00FA32B8  mov         ecx,dword ptr [this]  
00FA32BB  push        ecx  
00FA32BC  call        std::fill<char *,char> (0F9E839h)  
00FA32C1  add         esp,0Ch  
                  data[uiMaxSize] = '\0';
00FA32C4  mov         eax,dword ptr [this]  
00FA32C7  mov         byte ptr [eax+400h],0  

      

Note that when using cout <, it explicitly replaces the (55h) character instead of chr:

00FA327D  push        55h  

      

However, when used as a parameter in padding, it uses offset RepeatChar<85>'::

2 ':: chr (0FFE3BAh), as in:



00FA32AA  push        offset `RepeatChar<85>'::`2'::chr (0FFE3BAh)  

      

But memory location 0FFE3BAh contains 0. But if chr is used elsewhere, then it fills 55h at that location.

It looks like the code that generates the static section thinks that it has fully optimized chr, but in fact it is not.

Unfortunately, we don't have source code for VC ++, so this will remain a mystery until Microsoft fixes it.

EDIT:

The same code doesn't compile in g ++ 4.4.5. Well, it does compile fine, but generates code that depends on the outside, which doesn't seem to be accounted for, which makes the linker work with barf. When compiling with g ++, I got the following error code:

/tmp/cccGJmv9.o: In function `char const* RepeatChar<(char)85>(unsigned int)::FilledArray::FilledArray()':
b1.cpp:(.text+0x56): undefined reference to `chr'
b1.cpp:(.text+0xa5): undefined reference to `uiMaxSize'
b1.cpp:(.text+0xb2): undefined reference to `chr'
b1.cpp:(.text+0xc1): undefined reference to `uiMaxSize'
collect2: ld returned 1 exit status

      

This is consistent with the diagnosis, which apparently thought he was optimizing static constant variables, but in fact he didn't.

+2


source







All Articles