通过类型大小增加void *的正确方法,因为强制转换导致临时,而不是左值

时间:2013-03-26 18:25:21

标签: c++

在升级以下旧的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)
    }
}

1 个答案:

答案 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;