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;
}
source to share
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.
source to share