3

在升级以下旧 C++ 代码以在现代 Xcode 4.x 编译器下编译时,我发现原始开发人员使用了一个有效但应该避免的编程习惯——现在这是一个错误:

*((USHORT*) pvPixel)++ = uRG;   // copy red & green (2 bytes)

我明白了它的意图:将 unsigned short (uRG) 复制到 void 指针 (pvPixel) 指向的地址,然后增加适当的大小(在上述情况下为 2 个字节)。问题是投射 pvPixel 会导致一个临时的,而不是一个左值,这是不再允许的。

最初的开发者在几十个地方使用了这个成语——我可以在短时间内重写。但是,最好提供一个优雅且可读的解决方案,而不是蛮力地重写每一个事件。我可以想到几种可能的替代方案来对每次出现进行强力重写:宏、内联函数,也许是模板?

我的问题是:这个问题是否有任何 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)
    }
}
4

1 回答 1

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;
于 2013-03-26T20:40:03.290 回答