3

如果标记的行被注释掉,有人可以解释为什么以下代码在 Visual Studio C++ 2008/2010 上不起作用?是编译器错误还是我做错了什么?该代码应输出 10 个 U 的序列,但删除该行后它什么也不输出。在 FilledArray 构造函数中,变量 chr 变为 0。谢谢!

// 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;
}
4

1 回答 1

2

看起来像一个编译器错误。我将代码更改为以下内容:

#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;
}

然后拆解问题区域,即:

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

和:

            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  

请注意,当 cout << 使用时,它会显式替换字符 (55h) 来代替chr

00FA327D  push        55h  

但是,在填充中用作参数时,它使用偏移量RepeatChar<85>'::2'::chr (0FFE3BAh),如下所示:

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

但是内存位置 0FFE3BAh 包含一个 0。但是如果 chr 在其他地方使用,那么它会在该位置填充 55h。

看起来生成静态部分的代码认为它已经完全优化了chr,但实际上并没有。

不幸的是,我们没有 VC++ 的源代码,所以在微软修复它之前这仍然是一个谜。

编辑:

相同的代码不能在 g++ 4.4.5 中编译。好吧,它实际上编译得很好,但生成的代码依赖于它似乎遗漏的外部代码,这导致链接器出错。使用 g++ 编译时出现以下错误代码:

/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

这与它似乎认为它优化了静态 const 变量的诊断一致,但实际上并没有。

于 2013-02-13T14:44:31.097 回答