c++ - 为什么这段代码在 Visual Studio 2003 中编译?
问题描述
这可能是一个愚蠢的问题。
在将项目从 Visual Studio 2003 迁移到 2017 时,我注意到代码会在第 85 行出现“未定义标识符”错误。这对我来说很有意义,因为nCurrPel
在那个范围内似乎不存在。
但是,完全相同的代码似乎在 Visual Studio 2003 中编译得很好。这里发生了什么?
下面的完整代码,请参阅注释部分:
LTBOOL CompressLMData(const int *pData, int width, int height, int *pOutBuffer, int &outLen)
{
if((pData == NULL) || (pOutBuffer == NULL))
{
ASSERT(FALSE);
return FALSE;
}
if((width > LIGHTMAP_MAX_PIXELS_I) || (height > LIGHTMAP_MAX_PIXELS_I))
{
ASSERT(FALSE);
return FALSE;
}
int nBufferLen = width * height * 3;
int nSpanLen = 0;
int* pOutPos = pOutBuffer;
for(int nCurrPel = 0; nCurrPel < nBufferLen; nCurrPel += 3)
{
int nRunLen = 1;
for(int nRunPel = nCurrPel + 3; nRunPel < nBufferLen; nRunPel += 3, nRunLen++)
{
if(nRunLen > 127)
{
break;
}
if( (pData[nCurrPel + 0] != pData[nRunPel + 0]) ||
(pData[nCurrPel + 1] != pData[nRunPel + 1]) ||
(pData[nCurrPel + 2] != pData[nRunPel + 2]) )
{
break;
}
}
if(nRunLen >= 2)
{
if(nSpanLen > 0)
{
OutputSpan(false, nSpanLen, &pData[nCurrPel - nSpanLen * 3], pOutPos);
}
OutputSpan(true, nRunLen, &pData[nCurrPel], pOutPos);
nSpanLen = 0;
nCurrPel += (nRunLen - 1) * 3;
}
else
{
nSpanLen++;
if(nSpanLen > 127)
{
OutputSpan(false, nSpanLen, &pData[nCurrPel - (nSpanLen - 1) * 3], pOutPos);
nSpanLen = 0;
}
}
}
//How does this work? nCurrPel is not defined
if(nSpanLen > 0)
{
OutputSpan(false, nSpanLen, &pData[nCurrPel - nSpanLen * 3], pOutPos);
}
outLen = (int)(pOutPos - pOutBuffer);
ASSERT( (outLen >= 4 * (width * height / 128)) &&
(outLen <= (width * height * 3 + (width * height + 127) / 128)) );
return LTTRUE;
}
解决方案
这与for
循环的范围有关。
版本 8(2005、2003、2002、6.0 等)之前的 Microsoft Visual C++ 编译器将语句内for
声明的变量范围“提升”到父范围。在 Visual Studio 2008(版本 9)之后,编译器符合 C++ 规范,该规范要求这些变量的范围仅限于for
语句及其主体。
Visual C++ 2003 和 2005 接受的不兼容 C++:
cout << bar << endl; // error: `bar` isn't defined yet
for( int bar = 0; bar < 10; bar++ ) // `bar` is defined here and it can be used within the `for( ... )` statement parenthesis.
{
cout << bar << endl; // this
}
cout << bar << endl; // the life of `bar` extends after its `for` statement to the end of the parent scope
自 Visual C++ 2008 以来,生命周期bar
仅限于for
语句括号和语句体,而不是父范围:
cout << bar << endl; // error: `bar` isn't in-scope yet
for( int bar = 0; bar < 10; bar++ ) // `bar` is defined here and it can be used within the `for( ... )` statement parenthesis.
{
cout << bar << endl; // OK
}
cout << bar << endl; // error: `bar` is not in scope
要解决此问题,您可以手动声明和初始化for
父作用域中的循环变量,或使用单独的变量来保存最后一个值,如下所示:
方法 1:声明移至父范围:
int bar = 0;
for( ; bar < 10; bar++ )
{
cout << bar << endl;
}
cout << bar << endl;
方法 2:在父作用域中声明的单独变量:
int last_bar = 0; // Set an initial value in case the for loop body is never evaluated.
for( int bar = 0; bar < 10; bar++ )
{
cout << bar << endl;
last_bar = bar;
}
cout << last_bar << endl;
推荐阅读
- python - 无法加密最里面的文件
- algorithm - 绘制图像选择的算法
- typo3 - 如何让流畅的自动完成小部件在 TYPO3 v10 中工作
- r - 用两个(多个)条件制作图案
- javascript - Word JS - 插入表格标题、图形标题和公式
- python - 具有汉明距离的 vpVP 树的奇怪行为
- css - Vuetify v-textarea 在隐藏细节后产生空白
- openvpn - 如何创建一个tun接口?
- angular - 如何从Angular中具有相同名称(name = array [])的多个字段获取数组输入
- c++ - MFC SetRegistryKey 功能相反?我错过了什么?