在升级以下旧的C ++代码以在现代Xcode 4.x编译器下进行编译时,我发现原始开发人员使用的编程习惯用法有效,但应该避免 - 现在是一个错误:
*((USHORT*) pvPixel)++ = uRG; // copy red & green (2 bytes)
我看到了意图:将无符号短(uRG)复制到void指针(pvPixel)指向的地址,然后按适当的大小递增(在上面的情况下为2个字节)。问题是,施放pvPixel导致一个临时的,而不是左值,这是不再允许的。
原始开发人员在几十个地方使用这个成语 - 我可以在短时间内重写。但是,提供一个ELEGANT和READABLE解决方案会很好,而不是每次都发生暴力重写。我可以想到几种可能的替代方法来对每次出现的暴力重写:宏,内联函数,也许是模板?
我的问题是:这个问题有没有C ++语法/语言解决方案?什么方法可以为未来的开发人员提供最清晰的代码?
(下面两个示例函数):
void PrimSurfaceGDI3::mFillHLine( UINT uRGB, UINT uX, UINT uY, UINT uW )
{
LPVOID pvPixel;
if ( uW > 0 )
{
// obtain a pointer to a specified pixel in the surface
pvPixel = mPtr( uX, uY );
USHORT uRG = *(USHORT*) &uRGB;
BYTE uB = ((BYTE*) &uRGB)[2];
LPVOID pvEnd = (BYTE*) pvPixel + uW * 3;
while (pvPixel < pvEnd)
{
// The two lines below are now ILLEGAL in modern compilers because casting pvPixel to USHORT* or BYTE* results in a TEMPORARY, not an lvalue
*((USHORT*) pvPixel)++ = uRG; // copy red & green (2 bytes)
*((BYTE*) pvPixel)++ = uB; // copy blue (1 byte)
}
}
}
下面,这个习惯用法在for循环的重新初始化语句中使用:
void PrimSurfaceGDI3::mFillVLine( UINT uRGB, UINT uX, UINT uY, UINT uH )
{
LPVOID pvPixel = mPtr( uX, uY );
USHORT uRG = *(USHORT*) &uRGB;
BYTE uB = ((BYTE*) &uRGB)[2];
LPVOID pvEnd = (BYTE*) pvPixel + uH * muScan;
// The reinitialization statement is now ILLEGAL in modern compilers because casting pvPixel to BYTE* results in a TEMPORARY, not an lvalue
for ( ; pvPixel < pvEnd; ((BYTE*) pvPixel) += muScan)
{
*(USHORT*) pvPixel = uRG; // copy red & green (2 bytes)
((BYTE*) pvPixel)[2] = uB; // copy blue (1 byte)
}
}
答案 0 :(得分:3)
解决这个问题的方法之一可能是稍微改变一下。更改mPtr
,以便将指针(或容器引用)返回到包含三个字段的三字节类型,然后使用std::fill_n
用输入RGB填充它。然后函数缩小到这样的程度(这使编译器有很好的机会应用任何适当的优化):
void PrimSurfaceGDI3::mFillHLine( UINT uRGB, UINT uX, UINT uY, UINT uW )
{
if ( uW > 0 )
{
ColorRep pvPixel* = mPtr( uX, uY );
std::fill_n(pvPixel, uW, ColorRep(uRGB));
}
}
接下来,请注意原始的“优化”可能是一种去优化,因为它会导致所有错误对齐的双字节访问。
如果您想在代码中尽可能少地进行更改,则表示您接受此代码可能无法在除x86之外的任何体系结构上运行(由于访问不一致),并且您愿意使用-fno-strict-aliasing
(可能因为转换为不相关的类型而需要),然后您可以使用reinterpret_cast
来参考:
*(reinterpret_cast<unsigned short*&>(pvPixel))++ = uRG;