根据类型大小增加void*的正确方法,因为强制转换导致临时值,而不是左值
Proper method to increment a void* by type size because cast results in temporary, not lvalue
在升级以下旧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)
}
}
解决这个问题的一个更合理的方法可能是稍微重做。改变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;
相关文章:
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- HEX值到wchar_t字符(UTF-8)的转换
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将 Qvector<uint8_t> 转换为 QString
- 如何在cuSparse中使用cusparseXcoo2csr从coo转换为csc
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 在c++中使用nlohmann从类到json的转换
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 将公共递归转换为尾递归,因为大型输入的堆栈溢出
- 我想使用 std::stoi 函数在 cpp 中将字符串转换为整数,因为我想在字符串中找到不同数字的总和(在下级酶中)
- 使用静态转换,因为动态转换失败.不好的做法?
- isdigit() 和 isalnum() 给出错误,因为输入是一个常量字符并且无法转换。其他可能查看输入是否为数字的方法?
- 隐式用户定义的转换不起作用,因为在编译C 时无法识别运算符和转换构造函数
- 无法通过此操作,因为类型的错误转换
- C++无法将'long double'转换为'long double*',因为参数'1'为"long
- dll从VC++导入到VB函数的转换从dll返回错误,因为缺少链接库
- 根据类型大小增加void*的正确方法,因为强制转换导致临时值,而不是左值